Blender V4.3
wm_keymap.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cstring>
12#include <fmt/format.h>
13
14#include "DNA_object_types.h"
15#include "DNA_screen_types.h"
16#include "DNA_space_types.h"
17#include "DNA_userdef_types.h"
19#include "DNA_workspace_types.h"
20
21#include "CLG_log.h"
22#include "MEM_guardedalloc.h"
23
24#include "BLI_blenlib.h"
25#include "BLI_string_utils.hh"
26#include "BLI_utildefines.h"
27
28#include "BLF_api.hh"
29
30#include "UI_interface.hh"
31
32#include "BKE_context.hh"
33#include "BKE_global.hh"
34#include "BKE_idprop.hh"
35#include "BKE_main.hh"
36#include "BKE_screen.hh"
37#include "BKE_workspace.hh"
38
39#include "BLT_translation.hh"
40
41#include "RNA_access.hh"
42#include "RNA_enum_types.hh"
43
44#include "WM_api.hh"
45#include "WM_types.hh"
46#include "wm_event_system.hh"
47#include "wm_event_types.hh"
48
49#include "ED_screen.hh"
50
52 bool (*filter_fn)(const wmKeyMap *km, const wmKeyMapItem *kmi, void *user_data);
53 void *user_data;
54};
55
56/* -------------------------------------------------------------------- */
63{
64 wmKeyMapItem *kmin = static_cast<wmKeyMapItem *>(MEM_dupallocN(kmi));
65
66 kmin->prev = kmin->next = nullptr;
67 kmin->flag &= ~KMI_UPDATE;
68
69 if (kmin->properties) {
70 kmin->ptr = MEM_new<PointerRNA>("UserKeyMapItemPtr");
72
73 /* Signal for no context, see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
74 kmin->ptr->owner_id = nullptr;
75
77 kmin->ptr->data = kmin->properties;
78 }
79 else {
80 kmin->properties = nullptr;
81 kmin->ptr = nullptr;
82 }
83
84 return kmin;
85}
86
88{
89 /* Not the `kmi` itself. */
90 if (kmi->ptr) {
92 MEM_delete(kmi->ptr);
93 kmi->ptr = nullptr;
94 kmi->properties = nullptr;
95 }
96 else if (kmi->properties) {
98 kmi->properties = nullptr;
99 }
100}
101
103{
104 IDProperty *properties = kmi->properties;
105 kmi->properties = nullptr;
106 if (kmi->ptr) {
107 kmi->ptr->data = nullptr;
108 }
110 kmi->properties = properties;
111}
112
114{
115 WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
117
118 /* Signal for no context, see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
119 kmi->ptr->owner_id = nullptr;
120}
121
126static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi, const bool keep_properties)
127{
128 if (kmi->idname[0] == 0) {
129 BLI_assert(kmi->ptr == nullptr);
130 return;
131 }
132
133 if (kmi->ptr == nullptr) {
135 }
136 else {
138 if (ot) {
139 if (ot->srna != kmi->ptr->type) {
140 /* Matches #wm_keymap_item_properties_set but doesn't alloc new ptr. */
142 /* 'kmi->ptr->data' nullptr'd above, keep using existing properties.
143 * NOTE: the operators property types may have changed,
144 * we will need a more comprehensive sanitize function to support this properly.
145 */
146 if (kmi->properties) {
147 kmi->ptr->data = kmi->properties;
148 }
150
151 /* Signal for no context, see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
152 kmi->ptr->owner_id = nullptr;
153 }
154 }
155 else {
156 /* Zombie key-map item. */
157 if (keep_properties) {
159 }
160 else {
162 }
163 }
164 }
165}
166
168 const bool keep_properties)
169{
170 LISTBASE_FOREACH (wmKeyMap *, km, km_lb) {
171 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
172 wm_keymap_item_properties_update_ot(kmi, keep_properties);
173 }
174
175 LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
176 if (kmdi->add_item) {
177 wm_keymap_item_properties_update_ot(kmdi->add_item, keep_properties);
178 }
179 if (kmdi->remove_item) {
180 wm_keymap_item_properties_update_ot(kmdi->remove_item, keep_properties);
181 }
182 }
183 }
184}
185
187{
188 return (STREQ(a->idname, b->idname) &&
189 /* We do not really care about which Main we pass here, TBH. */
191 (a->flag & KMI_INACTIVE) == (b->flag & KMI_INACTIVE) && a->propvalue == b->propvalue);
192}
193
195{
196 return (wm_keymap_item_equals_result(a, b) && a->type == b->type && a->val == b->val &&
197 a->shift == b->shift && a->ctrl == b->ctrl && a->alt == b->alt && a->oskey == b->oskey &&
198 a->keymodifier == b->keymodifier && a->maptype == b->maptype &&
199 ((a->val != KM_CLICK_DRAG) || (a->direction == b->direction)) &&
200 ((ISKEYBOARD(a->type) == 0) ||
201 (a->flag & KMI_REPEAT_IGNORE) == (b->flag & KMI_REPEAT_IGNORE)));
202}
203
205{
206 if (LIKELY(kmi->ptr)) {
208 MEM_delete(kmi->ptr);
209
210 kmi->ptr = nullptr;
211 }
212 else if (kmi->properties) {
214 }
215
216 kmi->properties = properties;
217
219}
220
222{
223 if (ISTIMER(kmi->type)) {
224 return KMI_TYPE_TIMER;
225 }
226 if (ISKEYBOARD(kmi->type)) {
227 return KMI_TYPE_KEYBOARD;
228 }
229 if (ISMOUSE(kmi->type)) {
230 return KMI_TYPE_MOUSE;
231 }
232 if (ISNDOF(kmi->type)) {
233 return KMI_TYPE_NDOF;
234 }
235 if (kmi->type == KM_TEXTINPUT) {
236 return KMI_TYPE_TEXTINPUT;
237 }
238 if (ELEM(kmi->type, TABLET_STYLUS, TABLET_ERASER)) {
239 return KMI_TYPE_MOUSE;
240 }
241 return KMI_TYPE_KEYBOARD;
242}
243
246/* -------------------------------------------------------------------- */
253{
254 wmKeyMapDiffItem *kmdin = static_cast<wmKeyMapDiffItem *>(MEM_dupallocN(kmdi));
255
256 kmdin->next = kmdin->prev = nullptr;
257 if (kmdi->add_item) {
258 kmdin->add_item = wm_keymap_item_copy(kmdi->add_item);
259 }
260 if (kmdi->remove_item) {
262 }
263
264 return kmdin;
265}
266
268{
269 if (kmdi->remove_item) {
271 MEM_freeN(kmdi->remove_item);
272 }
273 if (kmdi->add_item) {
275 MEM_freeN(kmdi->add_item);
276 }
277}
278
281/* -------------------------------------------------------------------- */
289wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname, bool user_defined)
290{
291 BLI_assert(!BLI_findstring(&wm->keyconfigs, idname, offsetof(wmKeyConfig, idname)));
292 /* Create new configuration. */
293 wmKeyConfig *keyconf = static_cast<wmKeyConfig *>(
294 MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig"));
295 STRNCPY_UTF8(keyconf->idname, idname);
296 BLI_addtail(&wm->keyconfigs, keyconf);
297
298 if (user_defined) {
299 keyconf->flag |= KEYCONF_USER;
300 }
301
302 return keyconf;
303}
304
305wmKeyConfig *WM_keyconfig_ensure(wmWindowManager *wm, const char *idname, bool user_defined)
306{
307 wmKeyConfig *keyconf = static_cast<wmKeyConfig *>(
308 BLI_findstring(&wm->keyconfigs, idname, offsetof(wmKeyConfig, idname)));
309 if (keyconf) {
310 if (keyconf == wm->defaultconf) {
311 /* For default configuration, we need to keep keymap
312 * modal items and poll functions intact. */
313 LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) {
314 WM_keymap_clear(km);
315 }
316 }
317 else {
318 /* For user defined key configuration, clear all keymaps. */
319 WM_keyconfig_clear(keyconf);
320 }
321
322 return keyconf;
323 }
324
325 return WM_keyconfig_new(wm, idname, user_defined);
326}
327
329{
330 BLI_assert(BLI_findindex(&wm->keyconfigs, keyconf) != -1);
331 if (STREQLEN(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr))) {
332 STRNCPY(U.keyconfigstr, wm->defaultconf->idname);
333 U.runtime.is_dirty = true;
334 WM_keyconfig_update_tag(nullptr, nullptr);
335 }
336
337 BLI_remlink(&wm->keyconfigs, keyconf);
338 WM_keyconfig_free(keyconf);
339
340 /* Clear pointers. */
341 wmKeyConfig **keyconf_arr_p[] = {WM_KEYCONFIG_ARRAY_P(wm)};
342 for (int i = 0; i < ARRAY_SIZE(keyconf_arr_p); i++) {
343 wmKeyConfig **kc_p = keyconf_arr_p[i];
344 if (*kc_p == keyconf) {
345 *kc_p = nullptr;
346 }
347 }
348}
349
351{
352 LISTBASE_FOREACH_MUTABLE (wmKeyMap *, km, &keyconf->keymaps) {
353 WM_keymap_clear(km);
354 MEM_freeN(km);
355 }
356
357 BLI_listbase_clear(&keyconf->keymaps);
358}
359
361{
362 WM_keyconfig_clear(keyconf);
363 MEM_freeN(keyconf);
364}
365
367{
368 wmKeyConfig *keyconf;
369
370 /* First try from preset. */
371 keyconf = static_cast<wmKeyConfig *>(
372 BLI_findstring(&wm->keyconfigs, U.keyconfigstr, offsetof(wmKeyConfig, idname)));
373 if (keyconf) {
374 return keyconf;
375 }
376
377 /* Otherwise use default. */
378 return wm->defaultconf;
379}
380
381void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname)
382{
383 /* Setting a different key configuration as active:
384 * we ensure all is updated properly before and after making the change. */
385
387
388 STRNCPY(U.keyconfigstr, idname);
390 U.runtime.is_dirty = true;
391 }
392
393 WM_keyconfig_update_tag(nullptr, nullptr);
395}
396
399/* -------------------------------------------------------------------- */
405static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid)
406{
407 wmKeyMap *km = static_cast<wmKeyMap *>(MEM_callocN(sizeof(wmKeyMap), "keymap list"));
408
409 STRNCPY_UTF8(km->idname, idname);
410 km->spaceid = spaceid;
411 km->regionid = regionid;
412
413 {
414 const char *owner_id = RNA_struct_state_owner_get();
415 if (owner_id) {
416 STRNCPY(km->owner_id, owner_id);
417 }
418 }
419 return km;
420}
421
423{
424 wmKeyMap *keymapn = static_cast<wmKeyMap *>(MEM_dupallocN(keymap));
425
426 keymapn->modal_items = keymap->modal_items;
427 keymapn->poll = keymap->poll;
428 keymapn->poll_modal_item = keymap->poll_modal_item;
429 BLI_listbase_clear(&keymapn->items);
430 keymapn->flag &= ~(KEYMAP_UPDATE | KEYMAP_EXPANDED);
431
432 LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
434 BLI_addtail(&keymapn->items, kmdi_new);
435 }
436
437 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
438 wmKeyMapItem *kmi_new = wm_keymap_item_copy(kmi);
439 BLI_addtail(&keymapn->items, kmi_new);
440 }
441
442 return keymapn;
443}
444
446{
449 MEM_freeN(kmdi);
450 }
451
452 LISTBASE_FOREACH_MUTABLE (wmKeyMapItem *, kmi, &keymap->items) {
454 MEM_freeN(kmi);
455 }
456
458 BLI_listbase_clear(&keymap->items);
459}
460
461void WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
462{
463 BLI_assert(BLI_findindex(&keyconf->keymaps, keymap) != -1);
464 WM_keymap_clear(keymap);
465 BLI_remlink(&keyconf->keymaps, keymap);
466 MEM_freeN(keymap);
467}
468
470{
471 /* If we're tagged, only use compatible. */
472 if (keymap->owner_id[0] != '\0') {
473 const WorkSpace *workspace = CTX_wm_workspace(C);
474 if (BKE_workspace_owner_id_check(workspace, keymap->owner_id) == false) {
475 return false;
476 }
477 }
478
479 if (UNLIKELY(BLI_listbase_is_empty(&keymap->items))) {
480 /* Empty key-maps may be missing more there may be a typo in the name.
481 * Warn early to avoid losing time investigating each case.
482 * When developing a customized Blender though you may want empty keymaps. */
483 if (!U.app_template[0] &&
484 /* Fallback key-maps may be intentionally empty, don't flood the output. */
485 !BLI_str_endswith(keymap->idname, " (fallback)") &&
486 /* This is an exception which may be empty.
487 * Longer term we might want a flag to indicate an empty key-map is intended. */
488 !STREQ(keymap->idname, "Node Tool: Tweak") &&
489 /* Another exception: Asset shelf keymap is meant for add-ons to use, it's empty by
490 * default. */
491 !STREQ(keymap->idname, "Asset Shelf"))
492 {
493 CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname);
494 }
495 }
496
497 if (keymap->poll != nullptr) {
498 return keymap->poll(C);
499 }
500 return true;
501}
502
504{
505 kmi->type = params->type;
506 kmi->val = params->value;
507 kmi->keymodifier = params->keymodifier;
508 kmi->direction = params->direction;
509
510 if (params->modifier == KM_ANY) {
511 kmi->shift = kmi->ctrl = kmi->alt = kmi->oskey = KM_ANY;
512 }
513 else {
514 /* Only one of the flags should be set. */
515 BLI_assert(((params->modifier & (KM_SHIFT | KM_SHIFT_ANY)) != (KM_SHIFT | KM_SHIFT_ANY)) &&
516 ((params->modifier & (KM_CTRL | KM_CTRL_ANY)) != (KM_CTRL | KM_CTRL_ANY)) &&
517 ((params->modifier & (KM_ALT | KM_ALT_ANY)) != (KM_ALT | KM_ALT_ANY)) &&
518 ((params->modifier & (KM_OSKEY | KM_OSKEY_ANY)) != (KM_OSKEY | KM_OSKEY_ANY)));
519
520 kmi->shift = ((params->modifier & KM_SHIFT) ?
522 ((params->modifier & KM_SHIFT_ANY) ? KM_ANY : KM_NOTHING));
523 kmi->ctrl = ((params->modifier & KM_CTRL) ?
525 ((params->modifier & KM_CTRL_ANY) ? KM_ANY : KM_NOTHING));
526 kmi->alt = ((params->modifier & KM_ALT) ?
528 ((params->modifier & KM_ALT_ANY) ? KM_ANY : KM_NOTHING));
529 kmi->oskey = ((params->modifier & KM_OSKEY) ?
531 ((params->modifier & KM_OSKEY_ANY) ? KM_ANY : KM_NOTHING));
532 }
533}
534
535static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
536{
537 keymap->kmi_id++;
538 if ((keymap->flag & KEYMAP_USER) == 0) {
539 kmi->id = keymap->kmi_id;
540 }
541 else {
542 kmi->id = -keymap->kmi_id; /* User defined keymap entries have negative ids. */
543 }
544}
545
547 const char *idname,
549{
550 wmKeyMapItem *kmi = static_cast<wmKeyMapItem *>(
551 MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"));
552
553 BLI_addtail(&keymap->items, kmi);
554 STRNCPY(kmi->idname, idname);
555
558
559 keymap_item_set_id(keymap, kmi);
560
561 WM_keyconfig_update_tag(keymap, kmi);
562
563 return kmi;
564}
565
567{
568 wmKeyMapItem *kmi_dst = wm_keymap_item_copy(kmi_src);
569
570 BLI_addtail(&keymap->items, kmi_dst);
571
572 keymap_item_set_id(keymap, kmi_dst);
573
574 WM_keyconfig_update_tag(keymap, kmi_dst);
575
576 return kmi_dst;
577}
578
580{
581 BLI_assert(BLI_findindex(&keymap->items, kmi) != -1);
582 if (kmi->ptr) {
584 MEM_delete(kmi->ptr);
585 }
586 else if (kmi->properties) {
588 }
589 BLI_freelinkN(&keymap->items, kmi);
590
591 WM_keyconfig_update_tag(keymap, nullptr);
592}
593
596/* -------------------------------------------------------------------- */
605static void wm_keymap_addon_add(wmKeyMap *keymap, wmKeyMap *addonmap)
606{
607 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &addonmap->items) {
608 wmKeyMapItem *kmi_new = wm_keymap_item_copy(kmi);
609 keymap_item_set_id(keymap, kmi_new);
610 BLI_addhead(&keymap->items, kmi_new);
611 }
612}
613
615{
616 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
617 if (wm_keymap_item_equals(kmi, needle)) {
618 return kmi;
619 }
620 }
621
622 return nullptr;
623}
624
626{
627 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
628 if (wm_keymap_item_equals_result(kmi, needle)) {
629 return kmi;
630 }
631 }
632
633 return nullptr;
634}
635
636static void wm_keymap_diff(
637 wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km, wmKeyMap *orig_km, wmKeyMap *addon_km)
638{
639 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &from_km->items) {
640 wmKeyMapItem *to_kmi = WM_keymap_item_find_id(to_km, kmi->id);
641
642 if (!to_kmi) {
643 /* Remove item. */
644 wmKeyMapDiffItem *kmdi = static_cast<wmKeyMapDiffItem *>(
645 MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"));
646 kmdi->remove_item = wm_keymap_item_copy(kmi);
647 BLI_addtail(&diff_km->diff_items, kmdi);
648 }
649 else if (to_kmi && !wm_keymap_item_equals(kmi, to_kmi)) {
650 /* Replace item. */
651 wmKeyMapDiffItem *kmdi = static_cast<wmKeyMapDiffItem *>(
652 MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"));
653 kmdi->remove_item = wm_keymap_item_copy(kmi);
654 kmdi->add_item = wm_keymap_item_copy(to_kmi);
655 BLI_addtail(&diff_km->diff_items, kmdi);
656 }
657
658 /* Sync expanded flag back to original so we don't lose it on re-patch. */
659 if (to_kmi) {
660 wmKeyMapItem *orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id);
661
662 if (!orig_kmi && addon_km) {
663 orig_kmi = wm_keymap_find_item_equals(addon_km, kmi);
664 }
665
666 if (orig_kmi) {
667 orig_kmi->flag &= ~KMI_EXPANDED;
668 orig_kmi->flag |= (to_kmi->flag & KMI_EXPANDED);
669 }
670 }
671 }
672
673 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &to_km->items) {
674 if (kmi->id < 0) {
675 /* Add item. */
676 wmKeyMapDiffItem *kmdi = static_cast<wmKeyMapDiffItem *>(
677 MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem"));
678 kmdi->add_item = wm_keymap_item_copy(kmi);
679 BLI_addtail(&diff_km->diff_items, kmdi);
680 }
681 }
682}
683
684static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km)
685{
686 LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &diff_km->diff_items) {
687 /* Find item to remove. */
688 wmKeyMapItem *kmi_remove = nullptr;
689 if (kmdi->remove_item) {
690 kmi_remove = wm_keymap_find_item_equals(km, kmdi->remove_item);
691 if (!kmi_remove) {
692 kmi_remove = wm_keymap_find_item_equals_result(km, kmdi->remove_item);
693 }
694 }
695
696 /* Add item. */
697 if (kmdi->add_item) {
698 /* Do not re-add an already existing keymap item! See #42088. */
699 /* We seek only for exact copy here! See #42137. */
700 wmKeyMapItem *kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item);
701
702 /* If kmi_add is same as kmi_remove (can happen in some cases,
703 * typically when we got kmi_remove from #wm_keymap_find_item_equals_result()),
704 * no need to add or remove anything, see #45579. */
705
718 if (kmi_add != nullptr && kmi_add == kmi_remove) {
719 kmi_remove = nullptr;
720 }
721 /* Only if nothing to remove or item to remove found. */
722 else if (!kmi_add && (!kmdi->remove_item || kmi_remove)) {
723 kmi_add = wm_keymap_item_copy(kmdi->add_item);
724 kmi_add->flag |= KMI_USER_MODIFIED;
725
726 if (kmi_remove) {
727 kmi_add->flag &= ~KMI_EXPANDED;
728 kmi_add->flag |= (kmi_remove->flag & KMI_EXPANDED);
729 kmi_add->id = kmi_remove->id;
730 BLI_insertlinkbefore(&km->items, kmi_remove, kmi_add);
731 }
732 else {
733 keymap_item_set_id(km, kmi_add);
734 BLI_addtail(&km->items, kmi_add);
735 }
736 }
737 }
738
739 /* Remove item. */
740 if (kmi_remove) {
741 wm_keymap_item_free_data(kmi_remove);
742 BLI_freelinkN(&km->items, kmi_remove);
743 }
744 }
745}
746
748 wmKeyMap *defaultmap,
749 wmKeyMap *addonmap,
750 wmKeyMap *usermap)
751{
752 int expanded = 0;
753
754 /* Remove previous keymap in list, we will replace it. */
756 lb, defaultmap->idname, defaultmap->spaceid, defaultmap->regionid);
757 if (km) {
758 expanded = (km->flag & (KEYMAP_EXPANDED | KEYMAP_CHILDREN_EXPANDED));
759 WM_keymap_clear(km);
760 BLI_freelinkN(lb, km);
761 }
762
763 /* Copy new keymap from an existing one. */
764 if (usermap && !(usermap->flag & KEYMAP_DIFF)) {
765 /* For compatibility with old user preferences with non-diff
766 * keymaps we override the original entirely. */
767
768 km = wm_keymap_copy(usermap);
769
770 /* Try to find corresponding id's for items. */
771 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
772 wmKeyMapItem *orig_kmi = wm_keymap_find_item_equals(defaultmap, kmi);
773 if (!orig_kmi) {
774 orig_kmi = wm_keymap_find_item_equals_result(defaultmap, kmi);
775 }
776
777 if (orig_kmi) {
778 kmi->id = orig_kmi->id;
779 }
780 else {
781 kmi->id = -(km->kmi_id++);
782 }
783 }
784
785 km->flag |= KEYMAP_UPDATE; /* Update again to create diff. */
786 }
787 else {
788 km = wm_keymap_copy(defaultmap);
789 }
790
791 /* Add addon keymap items. */
792 if (addonmap) {
793 wm_keymap_addon_add(km, addonmap);
794 }
795
796 /* Tag as being user edited. */
797 if (usermap) {
799 }
800 km->flag |= KEYMAP_USER | expanded;
801
802 /* Apply user changes of diff keymap. */
803 if (usermap && (usermap->flag & KEYMAP_DIFF)) {
804 wm_keymap_patch(km, usermap);
805 }
806
807 /* Add to list. */
808 BLI_addtail(lb, km);
809
810 return km;
811}
812
814 wmKeyMap *defaultmap,
815 wmKeyMap *addonmap,
816 wmKeyMap *km)
817{
818 /* Create temporary default + addon keymap for diff. */
819 wmKeyMap *origmap = defaultmap;
820
821 if (addonmap) {
822 defaultmap = wm_keymap_copy(defaultmap);
823 wm_keymap_addon_add(defaultmap, addonmap);
824 }
825
826 /* Remove previous diff keymap in list, we will replace it. */
827 wmKeyMap *prevmap = WM_keymap_list_find(lb, km->idname, km->spaceid, km->regionid);
828 if (prevmap) {
829 WM_keymap_clear(prevmap);
830 BLI_freelinkN(lb, prevmap);
831 }
832
833 /* Create diff keymap. */
834 wmKeyMap *diffmap = wm_keymap_new(km->idname, km->spaceid, km->regionid);
835 diffmap->flag |= KEYMAP_DIFF;
836 if (defaultmap->flag & KEYMAP_MODAL) {
837 diffmap->flag |= KEYMAP_MODAL;
838 }
839 wm_keymap_diff(diffmap, defaultmap, km, origmap, addonmap);
840
841 /* Add to list if not empty. */
842 if (diffmap->diff_items.first) {
843 BLI_addtail(lb, diffmap);
844 }
845 else {
846 WM_keymap_clear(diffmap);
847 MEM_freeN(diffmap);
848 }
849
850 /* Free temporary default map. */
851 if (addonmap) {
852 WM_keymap_clear(defaultmap);
853 MEM_freeN(defaultmap);
854 }
855}
856
859/* -------------------------------------------------------------------- */
868wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid)
869{
870 LISTBASE_FOREACH (wmKeyMap *, km, lb) {
871 if (km->spaceid == spaceid && km->regionid == regionid) {
872 if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) {
873 return km;
874 }
875 }
876 }
877
878 return nullptr;
879}
880
882 const char *idname,
883 int spaceid,
884 int regionid)
885{
886 LISTBASE_FOREACH (wmKeyMap *, km, lb) {
887 if (ELEM(km->spaceid, spaceid, SPACE_EMPTY) && km->regionid == regionid) {
888 if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) {
889 return km;
890 }
891 }
892 }
893
894 return nullptr;
895}
896
897wmKeyMap *WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
898{
899 wmKeyMap *km = WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
900
901 if (km == nullptr) {
902 km = wm_keymap_new(idname, spaceid, regionid);
903 BLI_addtail(&keyconf->keymaps, km);
904
905 WM_keyconfig_update_tag(km, nullptr);
906 }
907
908 return km;
909}
910
911wmKeyMap *WM_keymap_find_all(wmWindowManager *wm, const char *idname, int spaceid, int regionid)
912{
913 return WM_keymap_list_find(&wm->userconf->keymaps, idname, spaceid, regionid);
914}
915
917 const char *idname,
918 int spaceid,
919 int regionid)
920{
921 return WM_keymap_list_find_spaceid_or_empty(&wm->userconf->keymaps, idname, spaceid, regionid);
922}
923
926/* -------------------------------------------------------------------- */
934 const char *idname,
935 const EnumPropertyItem *items)
936{
937 wmKeyMap *km = WM_keymap_ensure(keyconf, idname, SPACE_EMPTY, RGN_TYPE_WINDOW);
938 km->flag |= KEYMAP_MODAL;
939
940 /* Initialize modal items from default configuration. */
941 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
942 if (wm->defaultconf && wm->defaultconf != keyconf) {
943 wmKeyMap *defaultkm = WM_keymap_list_find(
945
946 if (defaultkm) {
947 km->modal_items = defaultkm->modal_items;
948 km->poll = defaultkm->poll;
949 km->poll_modal_item = defaultkm->poll_modal_item;
950 }
951 }
952
953 if (items) {
954 km->modal_items = items;
955 }
956
957 return km;
958}
959
960wmKeyMap *WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
961{
962 LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) {
963 if (km->flag & KEYMAP_MODAL) {
964 if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) {
965 return km;
966 }
967 }
968 }
969
970 return nullptr;
971}
972
974{
975 wmKeyMapItem *kmi = static_cast<wmKeyMapItem *>(
976 MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"));
977
978 BLI_addtail(&km->items, kmi);
979 kmi->propvalue = value;
980
982
983 keymap_item_set_id(km, kmi);
984
986
987 return kmi;
988}
989
992 const char *value)
993{
994 wmKeyMapItem *kmi = static_cast<wmKeyMapItem *>(
995 MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"));
996
997 BLI_addtail(&km->items, kmi);
998 STRNCPY(kmi->propvalue_str, value);
999
1001
1002 keymap_item_set_id(km, kmi);
1003
1004 WM_keyconfig_update_tag(km, kmi);
1005
1006 return kmi;
1007}
1008
1010 const wmKeyMapItem *kmi,
1011 const int propvalue)
1012{
1013 if (km->flag & KEYMAP_MODAL) {
1014 kmi = static_cast<const wmKeyMapItem *>(kmi ? kmi->next : km->items.first);
1015 for (; kmi; kmi = kmi->next) {
1016 if (kmi->propvalue == propvalue) {
1017 return kmi;
1018 }
1019 }
1020 }
1021 else {
1022 BLI_assert_msg(0, "called with non modal keymap");
1023 }
1024
1025 return nullptr;
1026}
1027
1028const wmKeyMapItem *WM_modalkeymap_find_propvalue(const wmKeyMap *km, const int propvalue)
1029{
1030 return wm_modalkeymap_find_propvalue_iter(km, nullptr, propvalue);
1031}
1032
1033void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
1034{
1035 wmOperatorType *ot = WM_operatortype_find(opname, false);
1036
1037 if (ot) {
1038 ot->modalkeymap = km;
1039 }
1040 else {
1041 CLOG_ERROR(WM_LOG_KEYMAPS, "unknown operator '%s'", opname);
1042 }
1043}
1044
1046{
1047 /* Here we convert propvalue string values delayed, due to python keymaps
1048 * being created before the actual modal keymaps, so no modal_items. */
1049
1050 if (km && (km->flag & KEYMAP_MODAL) && !km->modal_items) {
1051 if (wm->defaultconf == nullptr) {
1052 return;
1053 }
1054
1055 wmKeyMap *defaultkm = WM_keymap_list_find(
1057 if (!defaultkm) {
1058 return;
1059 }
1060
1061 km->modal_items = defaultkm->modal_items;
1062 km->poll = defaultkm->poll;
1063 km->poll_modal_item = defaultkm->poll_modal_item;
1064
1065 if (km->modal_items) {
1066 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
1067 if (kmi->propvalue_str[0]) {
1068 int propvalue;
1069 if (RNA_enum_value_from_id(static_cast<const EnumPropertyItem *>(km->modal_items),
1070 kmi->propvalue_str,
1071 &propvalue))
1072 {
1073 kmi->propvalue = propvalue;
1074 }
1075 kmi->propvalue_str[0] = '\0';
1076 }
1077 }
1078 }
1079 }
1080}
1081
1084/* -------------------------------------------------------------------- */
1088static const char *key_event_glyph_or_text(const int font_id,
1089 const char *text,
1090 const char *single_glyph)
1091{
1092 BLI_assert(single_glyph == nullptr || (BLI_strlen_utf8(single_glyph) == 1));
1093 return (single_glyph && BLF_has_glyph(font_id, BLI_str_utf8_as_unicode_or_error(single_glyph))) ?
1094 single_glyph :
1095 text;
1096}
1097
1098const char *WM_key_event_string(const short type, const bool compact)
1099{
1100 if (compact) {
1101 /* String storing a single unicode character or nullptr. */
1102 const char *single_glyph = nullptr;
1103 int font_id = BLF_default();
1104 const enum {
1105 UNIX,
1106 MACOS,
1107 MSWIN,
1108 } platform =
1109
1110#if defined(__APPLE__)
1111 MACOS
1112#elif defined(_WIN32)
1113 MSWIN
1114#else
1115 UNIX
1116#endif
1117 ;
1118
1119 switch (type) {
1120 case EVT_LEFTSHIFTKEY:
1121 case EVT_RIGHTSHIFTKEY: {
1122 if (platform == MACOS) {
1123 single_glyph = BLI_STR_UTF8_UPWARDS_WHITE_ARROW;
1124 }
1126 font_id, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Shift"), single_glyph);
1127 }
1128 case EVT_LEFTCTRLKEY:
1129 case EVT_RIGHTCTRLKEY:
1130 if (platform == MACOS) {
1132 }
1133 return IFACE_("Ctrl");
1134 case EVT_LEFTALTKEY:
1135 case EVT_RIGHTALTKEY: {
1136 if (platform == MACOS) {
1137 /* Option symbol on Mac keyboard. */
1138 single_glyph = BLI_STR_UTF8_OPTION_KEY;
1139 }
1140 return key_event_glyph_or_text(font_id, IFACE_("Alt"), single_glyph);
1141 }
1142 case EVT_OSKEY: {
1143 if (platform == MACOS) {
1146 }
1147 if (platform == MSWIN) {
1150 }
1151 return IFACE_("OS");
1152 }
1153 case EVT_TABKEY:
1156 case EVT_BACKSPACEKEY:
1158 case EVT_ESCKEY:
1159 if (platform == MACOS) {
1161 }
1162 return key_event_glyph_or_text(font_id, IFACE_("Esc"), single_glyph);
1163 case EVT_RETKEY:
1165 case EVT_SPACEKEY:
1166 return key_event_glyph_or_text(font_id, IFACE_("Space"), BLI_STR_UTF8_OPEN_BOX);
1167 case EVT_LEFTARROWKEY:
1169 case EVT_UPARROWKEY:
1171 case EVT_RIGHTARROWKEY:
1173 case EVT_DOWNARROWKEY:
1175 }
1176 }
1177
1178 const EnumPropertyItem *it;
1179 const int i = RNA_enum_from_value(rna_enum_event_type_items, int(type));
1180
1181 if (i == -1) {
1182 return "";
1183 }
1185
1186 /* We first try enum items' description (abused as short-name here),
1187 * and fall back to usual name if empty. */
1188 if (compact && it->description[0]) {
1189 /* XXX No context for enum descriptions... In practice shall not be an issue though. */
1190 return IFACE_(it->description);
1191 }
1192
1193 return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
1194}
1195
1196std::optional<std::string> WM_keymap_item_raw_to_string(const short shift,
1197 const short ctrl,
1198 const short alt,
1199 const short oskey,
1200 const short keymodifier,
1201 const short val,
1202 const short type,
1203 const bool compact)
1204{
1205 /* TODO: also support (some) value, like e.g. double-click? */
1207
1208 const char *space = " ";
1209
1210 if (shift == KM_ANY && ctrl == KM_ANY && alt == KM_ANY && oskey == KM_ANY) {
1211 /* Don't show anything for any mapping. */
1212 }
1213 else {
1214 if (shift) {
1215 result_array.append(WM_key_event_string(EVT_LEFTSHIFTKEY, true));
1216 result_array.append(space);
1217 }
1218 if (ctrl) {
1219 result_array.append(WM_key_event_string(EVT_LEFTCTRLKEY, true));
1220 result_array.append(space);
1221 }
1222 if (alt) {
1223 result_array.append(WM_key_event_string(EVT_LEFTALTKEY, true));
1224 result_array.append(space);
1225 }
1226 if (oskey) {
1227 result_array.append(WM_key_event_string(EVT_OSKEY, true));
1228 result_array.append(space);
1229 }
1230 }
1231
1232 if (keymodifier) {
1233 result_array.append(WM_key_event_string(keymodifier, compact));
1234 result_array.append(space);
1235 }
1236
1237 if (type) {
1238 if (val == KM_DBL_CLICK) {
1239 result_array.append(IFACE_("dbl-"));
1240 }
1241 else if (val == KM_CLICK_DRAG) {
1242 result_array.append(IFACE_("drag-"));
1243 }
1244 result_array.append(WM_key_event_string(type, compact));
1245 }
1246
1247 if (!result_array.is_empty() && (result_array.last() == space)) {
1248 result_array.remove_last();
1249 }
1250
1251 return fmt::to_string(fmt::join(result_array, ""));
1252}
1253
1254std::optional<std::string> WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact)
1255{
1257 kmi->shift, kmi->ctrl, kmi->alt, kmi->oskey, kmi->keymodifier, kmi->val, kmi->type, compact);
1258}
1259
1260std::optional<std::string> WM_modalkeymap_items_to_string(const wmKeyMap *km,
1261 const int propvalue,
1262 const bool compact)
1263{
1264 const wmKeyMapItem *kmi;
1265 if (km == nullptr || (kmi = WM_modalkeymap_find_propvalue(km, propvalue)) == nullptr) {
1266 return std::nullopt;
1267 }
1268
1269 std::string result;
1270 do {
1271 result += WM_keymap_item_to_string(kmi, compact).value_or("");
1272
1273 if ((kmi = wm_modalkeymap_find_propvalue_iter(km, kmi, propvalue)) == nullptr) {
1274 break;
1275 }
1276 result += '/';
1277 } while (true);
1278
1279 return result;
1280}
1281
1283 const int propvalue,
1284 const bool compact)
1285{
1286 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
1287 wmKeyMap *keymap = WM_keymap_active(wm, ot->modalkeymap);
1288 return WM_modalkeymap_items_to_string(keymap, propvalue, compact);
1289}
1290
1293/* -------------------------------------------------------------------- */
1298 const char *opname,
1299 IDProperty *properties,
1300 const bool is_strict,
1302{
1303 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
1304 /* Skip disabled keymap items, see: #38447. */
1305 if (kmi->flag & KMI_INACTIVE) {
1306 continue;
1307 }
1308 if (!STREQ(kmi->idname, opname)) {
1309 continue;
1310 }
1311
1312 bool kmi_match = false;
1313 if (properties) {
1314/* Example of debugging keymaps. */
1315#if 0
1316 if (kmi->ptr) {
1317 if (STREQ("MESH_OT_rip_move", opname)) {
1318 printf("OPERATOR\n");
1319 IDP_print(properties);
1320 printf("KEYMAP\n");
1321 IDP_print(kmi->ptr->data);
1322 }
1323 }
1324#endif
1325
1326 if (kmi->ptr && IDP_EqualsProperties_ex(
1327 properties, static_cast<const IDProperty *>(kmi->ptr->data), is_strict))
1328 {
1329 kmi_match = true;
1330 }
1331 /* Debug only, helps spotting mismatches between menu entries and shortcuts! */
1332 else if (G.debug & G_DEBUG_WM) {
1333 if (is_strict && kmi->ptr) {
1334 wmOperatorType *ot = WM_operatortype_find(opname, true);
1335 if (ot) {
1336 /* Make a copy of the properties and set unset ones to their default values. */
1337 IDProperty *properties_default = IDP_CopyProperty(
1338 static_cast<const IDProperty *>(kmi->ptr->data));
1339
1340 PointerRNA opptr = RNA_pointer_create(nullptr, ot->srna, properties_default);
1341 WM_operator_properties_default(&opptr, true);
1342
1343 if (IDP_EqualsProperties_ex(properties, properties_default, is_strict)) {
1344 std::string kmi_str = WM_keymap_item_to_string(kmi, false).value_or("");
1345 /* NOTE: given properties could come from other things than menu entry. */
1346 printf(
1347 "%s: Some set values in menu entry match default op values, "
1348 "this might not be desired!\n",
1349 opname);
1350 printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str.c_str());
1351#ifndef NDEBUG
1352# ifdef WITH_PYTHON
1353 printf("OPERATOR\n");
1354 IDP_print(properties);
1355 printf("KEYMAP\n");
1356 IDP_print(static_cast<IDProperty *>(kmi->ptr->data));
1357# endif
1358#endif
1359 printf("\n");
1360 }
1361
1362 IDP_FreeProperty(properties_default);
1363 }
1364 }
1365 }
1366 }
1367 else {
1368 kmi_match = true;
1369 }
1370
1371 if (kmi_match) {
1372 if ((params == nullptr) || params->filter_fn(keymap, kmi, params->user_data)) {
1373 return kmi;
1374 }
1375 }
1376 }
1377 return nullptr;
1378}
1379
1381 wmWindowManager *wm,
1382 wmWindow *win,
1383 ListBase *handlers,
1384 const char *opname,
1385 wmOperatorCallContext /*opcontext*/,
1386 IDProperty *properties,
1387 const bool is_strict,
1389 wmKeyMap **r_keymap)
1390{
1391 /* Find keymap item in handlers. */
1392 LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
1393 if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
1394 wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
1396 WM_event_get_keymaps_from_handler(wm, win, handler, &km_result);
1397 for (int km_index = 0; km_index < km_result.keymaps_len; km_index++) {
1398 wmKeyMap *keymap = km_result.keymaps[km_index];
1399 if (WM_keymap_poll((bContext *)C, keymap)) {
1401 keymap, opname, properties, is_strict, params);
1402 if (kmi != nullptr) {
1403 if (r_keymap) {
1404 *r_keymap = keymap;
1405 }
1406 return kmi;
1407 }
1408 }
1409 }
1410 }
1411 }
1412 /* Ensure un-initialized keymap is never used. */
1413 if (r_keymap) {
1414 *r_keymap = nullptr;
1415 }
1416 return nullptr;
1417}
1418
1420 const char *opname,
1421 wmOperatorCallContext opcontext,
1422 IDProperty *properties,
1423 const bool is_strict,
1425 wmKeyMap **r_keymap)
1426{
1428 wmWindow *win = CTX_wm_window(C);
1429 ScrArea *area = CTX_wm_area(C);
1430 ARegion *region = CTX_wm_region(C);
1431 wmKeyMapItem *found = nullptr;
1432
1433 /* Look into multiple handler lists to find the item. */
1434 if (win) {
1436 wm,
1437 win,
1438 &win->modalhandlers,
1439 opname,
1440 opcontext,
1441 properties,
1442 is_strict,
1443 params,
1444 r_keymap);
1445 if (found == nullptr) {
1447 C, wm, win, &win->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1448 }
1449 }
1450
1451 if (area && found == nullptr) {
1453 C, wm, win, &area->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
1454 }
1455
1456 if (found == nullptr) {
1458 if (area) {
1459 if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
1461 }
1462
1463 if (region) {
1465 wm,
1466 win,
1467 &region->handlers,
1468 opname,
1469 opcontext,
1470 properties,
1471 is_strict,
1472 params,
1473 r_keymap);
1474 }
1475 }
1476 }
1478 if (!(region && region->regiontype == RGN_TYPE_CHANNELS)) {
1480 }
1481
1482 if (region) {
1484 wm,
1485 win,
1486 &region->handlers,
1487 opname,
1488 opcontext,
1489 properties,
1490 is_strict,
1491 params,
1492 r_keymap);
1493 }
1494 }
1496 if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
1498 }
1499
1500 if (region) {
1502 wm,
1503 win,
1504 &region->handlers,
1505 opname,
1506 opcontext,
1507 properties,
1508 is_strict,
1509 params,
1510 r_keymap);
1511 }
1512 }
1513 else {
1514 if (region) {
1516 wm,
1517 win,
1518 &region->handlers,
1519 opname,
1520 opcontext,
1521 properties,
1522 is_strict,
1523 params,
1524 r_keymap);
1525 }
1526 }
1527 }
1528
1529 return found;
1530}
1531
1533 const char *opname,
1534 wmOperatorCallContext opcontext,
1535 IDProperty *properties,
1536 bool is_strict,
1538 wmKeyMap **r_keymap)
1539{
1540 /* XXX Hack! Macro operators in menu entry have their whole props defined,
1541 * which is not the case for relevant keymap entries.
1542 * Could be good to check and harmonize this,
1543 * but for now always compare non-strict in this case. */
1544 wmOperatorType *ot = WM_operatortype_find(opname, true);
1545 if (ot) {
1546 is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0);
1547 }
1548
1550 C, opname, opcontext, properties, is_strict, params, r_keymap);
1551
1552 /* This block is *only* useful in one case: when op uses an enum menu in its prop member
1553 * (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle,
1554 * since now any enum prop may be used in UI (specified by name), ot->prop is not so much used...
1555 * Otherwise:
1556 * * If non-strict, unset properties always match set ones in IDP_EqualsProperties_ex.
1557 * * If strict, unset properties never match set ones in IDP_EqualsProperties_ex,
1558 * and we do not want that to change (else we get things like #41757)!
1559 * ...so in either case, re-running a comparison with unset props set to default is useless.
1560 */
1561 if (!found && properties) {
1562 if (ot && ot->prop) { /* XXX Shall we also check ot->prop is actually an enum? */
1563 /* Make a copy of the properties and unset the 'ot->prop' one if set. */
1564 IDProperty *properties_temp = IDP_CopyProperty(properties);
1565
1566 PointerRNA opptr = RNA_pointer_create(nullptr, ot->srna, properties_temp);
1567
1568 if (RNA_property_is_set(&opptr, ot->prop)) {
1569 /* For operator that has enum menu,
1570 * unset it so its value does not affect comparison result. */
1571 RNA_property_unset(&opptr, ot->prop);
1572
1574 C, opname, opcontext, properties_temp, is_strict, params, r_keymap);
1575 }
1576
1577 IDP_FreeProperty(properties_temp);
1578 }
1579 }
1580
1581 /* Debug only, helps spotting mismatches between menu entries and shortcuts! */
1582 if (G.debug & G_DEBUG_WM) {
1583 if (!found && is_strict && properties) {
1584 if (ot) {
1585 /* Make a copy of the properties and set unset ones to their default values. */
1586 IDProperty *properties_default = IDP_CopyProperty(properties);
1587
1588 PointerRNA opptr = RNA_pointer_create(nullptr, ot->srna, properties_default);
1589 WM_operator_properties_default(&opptr, true);
1590
1591 wmKeyMap *km;
1593 C, opname, opcontext, properties_default, is_strict, params, &km);
1594 if (kmi) {
1595 std::string kmi_str = WM_keymap_item_to_string(kmi, false).value_or("");
1596 printf(
1597 "%s: Some set values in keymap entry match default op values, "
1598 "this might not be desired!\n",
1599 opname);
1600 printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str.c_str());
1601#ifndef NDEBUG
1602# ifdef WITH_PYTHON
1603 printf("OPERATOR\n");
1604 IDP_print(properties);
1605 printf("KEYMAP\n");
1606 IDP_print(static_cast<IDProperty *>(kmi->ptr->data));
1607# endif
1608#endif
1609 printf("\n");
1610 }
1611
1612 IDP_FreeProperty(properties_default);
1613 }
1614 }
1615 }
1616
1617 return found;
1618}
1619
1620static bool kmi_filter_is_visible(const wmKeyMap * /*km*/,
1621 const wmKeyMapItem *kmi,
1622 void * /*user_data*/)
1623{
1624 return ((WM_key_event_string(kmi->type, false)[0] != '\0') &&
1625 (IS_EVENT_ACTIONZONE(kmi->type) == false));
1626}
1627
1628std::optional<std::string> WM_key_event_operator_string(const bContext *C,
1629 const char *opname,
1630 wmOperatorCallContext opcontext,
1631 IDProperty *properties,
1632 const bool is_strict)
1633{
1635 params.filter_fn = kmi_filter_is_visible;
1636 params.user_data = nullptr;
1638 C, opname, opcontext, properties, is_strict, &params, nullptr);
1639 if (kmi) {
1640 return WM_keymap_item_to_string(kmi, false);
1641 }
1642
1643 /* Check UI state (non key-map actions for UI regions). */
1644 if (std::optional<std::string> result = UI_key_event_operator_string(
1645 C, opname, properties, is_strict))
1646 {
1647 return result;
1648 }
1649
1650 return std::nullopt;
1651}
1652
1654 const wmKeyMapItem *kmi,
1655 void *user_data)
1656{
1657 short *mask_pair = static_cast<short int *>(user_data);
1658 return ((WM_event_type_mask_test(kmi->type, eEventType_Mask(mask_pair[0])) == true) &&
1659 (WM_event_type_mask_test(kmi->type, eEventType_Mask(mask_pair[1])) == false) &&
1660 kmi_filter_is_visible(km, kmi, user_data));
1661}
1662
1664 const char *opname,
1665 wmOperatorCallContext opcontext,
1666 IDProperty *properties,
1667 const short include_mask,
1668 const short exclude_mask,
1669 wmKeyMap **r_keymap)
1670{
1671 short user_data_mask[2] = {include_mask, exclude_mask};
1672 bool use_mask = (include_mask != EVT_TYPE_MASK_ALL) || (exclude_mask != 0);
1675 params.user_data = use_mask ? user_data_mask : nullptr;
1676 return wm_keymap_item_find(C, opname, opcontext, properties, true, &params, r_keymap);
1677}
1678
1680 const char *opname,
1681 IDProperty *properties,
1682 const short include_mask,
1683 const short exclude_mask)
1684{
1685 short user_data_mask[2] = {include_mask, exclude_mask};
1686 bool use_mask = (include_mask != EVT_TYPE_MASK_ALL) || (exclude_mask != 0);
1689 params.user_data = use_mask ? user_data_mask : nullptr;
1690
1691 return wm_keymap_item_find_in_keymap(keymap, opname, properties, true, &params);
1692}
1693
1695{
1696 if (k1->flag & KMI_INACTIVE || k2->flag & KMI_INACTIVE) {
1697 return false;
1698 }
1699
1700 /* Take event mapping into account. */
1701 int k1type = WM_userdef_event_map(k1->type);
1702 int k2type = WM_userdef_event_map(k2->type);
1703
1704 if (k1type != KM_ANY && k2type != KM_ANY && k1type != k2type) {
1705 return false;
1706 }
1707
1708 if (k1->val != KM_ANY && k2->val != KM_ANY) {
1709 /* Take click, press, release conflict into account. */
1710 if (k1->val == KM_CLICK && ELEM(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) {
1711 return false;
1712 }
1713 if (k2->val == KM_CLICK && ELEM(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) {
1714 return false;
1715 }
1716 if (k1->val != k2->val) {
1717 return false;
1718 }
1719 if (k1->val == KM_CLICK_DRAG && (k1->direction != k2->direction)) {
1720 return false;
1721 }
1722 }
1723
1724 if (k1->shift != KM_ANY && k2->shift != KM_ANY && k1->shift != k2->shift) {
1725 return false;
1726 }
1727
1728 if (k1->ctrl != KM_ANY && k2->ctrl != KM_ANY && k1->ctrl != k2->ctrl) {
1729 return false;
1730 }
1731
1732 if (k1->alt != KM_ANY && k2->alt != KM_ANY && k1->alt != k2->alt) {
1733 return false;
1734 }
1735
1736 if (k1->oskey != KM_ANY && k2->oskey != KM_ANY && k1->oskey != k2->oskey) {
1737 return false;
1738 }
1739
1740 if (k1->keymodifier != k2->keymodifier) {
1741 return false;
1742 }
1743
1744 return true;
1745}
1746
1749/* -------------------------------------------------------------------- */
1757/* So operator removal can trigger update. */
1758enum {
1760
1761 /* Ensure all wmKeyMap have their operator types validated after removing an operator. */
1763
1765};
1766
1768
1770#ifndef NDEBUG
1772#endif
1773
1775{
1776 /* Quick tag to do delayed keymap updates. */
1778
1779 if (keymap) {
1780 keymap->flag |= KEYMAP_UPDATE;
1781 }
1782 if (kmi) {
1783 kmi->flag |= KMI_UPDATE;
1784 }
1785}
1786
1791
1792/* NOTE(@ideasman42): regarding suppressing updates.
1793 * If this becomes a common operation it would be better use something more general,
1794 * a key-map flag for e.g. to signify that the key-map is stored outside of a #wmKeyConfig
1795 * and should not receive updates on modification. At the moment this has the down-side of
1796 * needing to be supported in quite a few places for something which isn't used much.
1797 * Since the use case for this is limited, add functions to begin/end suppression.
1798 * If these end up being used a lot we can consider alternatives. */
1799
1808
1818
1823
1825{
1826 wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_POSTPONE;
1827}
1828
1830{
1831 int update = (km->flag & KEYMAP_UPDATE);
1832 km->flag &= ~KEYMAP_UPDATE;
1833
1834 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
1835 update = update || (kmi->flag & KMI_UPDATE);
1836 kmi->flag &= ~KMI_UPDATE;
1837 }
1838
1839 return (update != 0);
1840}
1841
1843{
1844 wmKeyConfig *keyconf = WM_keyconfig_active(wm);
1845 wmKeyMap *keymap = WM_keymap_list_find(&keyconf->keymaps, km->idname, km->spaceid, km->regionid);
1846 if (!keymap && wm->defaultconf) {
1847 keymap = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, km->spaceid, km->regionid);
1848 }
1849
1850 return keymap;
1851}
1852
1854{
1855 WM_keyconfig_update_ex(wm, false);
1856}
1857
1858void WM_keyconfig_update_ex(wmWindowManager *wm, bool keep_properties)
1859{
1860 if (wm_keymap_update_flag == 0) {
1861 return;
1862 }
1863
1864 bool compat_update = false;
1865
1866 /* Update drop-boxes when the operators have been added or removed. While this isn't an ideal
1867 * place to update drop-boxes, they share characteristics with key-map items.
1868 * We could consider renaming this to API function so it's not only relating to keymaps. */
1869 bool dropbox_update = false;
1870
1871 /* Postpone update until after the key-map has been initialized
1872 * to ensure add-ons have been loaded, see: #113603. */
1874 return;
1875 }
1876
1878 /* One or more operator-types have been removed, this won't happen often
1879 * but when it does we have to check _every_ key-map item. */
1880 wm_keymap_item_properties_update_ot_from_list(&U.user_keymaps, keep_properties);
1882 wm_keymap_item_properties_update_ot_from_list(&kc->keymaps, keep_properties);
1883 }
1884
1885 /* An operator has been removed, refresh. */
1886 dropbox_update = true;
1887
1888 wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_OPERATORTYPE;
1889 }
1890
1892 /* Update operator properties for non-modal user keymaps. */
1893 LISTBASE_FOREACH (wmKeyMap *, km, &U.user_keymaps) {
1894 if ((km->flag & KEYMAP_MODAL) == 0) {
1895 LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
1896 if (kmdi->add_item) {
1897 wm_keymap_item_properties_set(kmdi->add_item);
1898 }
1899 if (kmdi->remove_item) {
1900 wm_keymap_item_properties_set(kmdi->remove_item);
1901 }
1902 }
1903
1904 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
1906 }
1907 }
1908 }
1909
1910 /* Update `U.user_keymaps` with user key configuration changes. */
1911 LISTBASE_FOREACH (wmKeyMap *, km, &wm->userconf->keymaps) {
1912 /* Only diff if the user keymap was modified. */
1914 /* Find keymaps. */
1915 wmKeyMap *defaultmap = wm_keymap_preset(wm, km);
1916 wmKeyMap *addonmap = WM_keymap_list_find(
1917 &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
1918
1919 /* Diff. */
1920 if (defaultmap) {
1921 wm_keymap_diff_update(&U.user_keymaps, defaultmap, addonmap, km);
1922 }
1923 }
1924 }
1925
1926 /* Create user key configuration from preset + addon + user preferences. */
1928 /* Find keymaps. */
1929 wmKeyMap *defaultmap = wm_keymap_preset(wm, km);
1930 wmKeyMap *addonmap = WM_keymap_list_find(
1931 &wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
1932 wmKeyMap *usermap = WM_keymap_list_find(
1933 &U.user_keymaps, km->idname, km->spaceid, km->regionid);
1934
1935 /* For now only the default map defines modal key-maps,
1936 * if we support modal keymaps for 'addonmap', these will need to be enabled too. */
1937 wm_user_modal_keymap_set_items(wm, defaultmap);
1938
1939 /* Add. */
1941 &wm->userconf->keymaps, defaultmap, addonmap, usermap);
1942
1943 if (kmn) {
1944 kmn->modal_items = km->modal_items;
1945 kmn->poll = km->poll;
1946 kmn->poll_modal_item = km->poll_modal_item;
1947 }
1948
1949 /* In case of old non-diff keymaps, force extra update to create diffs. */
1950 compat_update = compat_update || (usermap && !(usermap->flag & KEYMAP_DIFF));
1951 }
1952
1953 /* An operator may have been added, refresh. */
1954 dropbox_update = true;
1955
1956 wm_keymap_update_flag &= ~WM_KEYMAP_UPDATE_RECONFIGURE;
1957 }
1958
1960
1961 if (compat_update) {
1962 WM_keyconfig_update_tag(nullptr, nullptr);
1964 }
1965
1966 if (dropbox_update) {
1968 }
1969
1970 /* NOTE(@ideasman42): open preferences will contain "stale" #wmKeyMapItem data.
1971 *
1972 * The common case this solves is using Blender with the key-map editor open,
1973 * an action in the view-port for e.g. may manipulate the key-map causing it to be rebuilt.
1974 * Later interaction with the key-map editor may then attempt to access freed data.
1975 *
1976 * Take care, this is _not_ fool proof because it's possible:
1977 * - Key-map options to be shown in any region (using scripts).
1978 * - Key-map re-generation could happen while the preferences is open,
1979 * where the data becomes stale before the UI has a chance to redraw.
1980 *
1981 * In practice both cases are quite unlikely though. */
1982 if (U.space_data.section_active == USER_SECTION_KEYMAP) {
1983 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1984 bScreen *screen = WM_window_get_active_screen(win);
1985 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1986 if (area->spacetype == SPACE_USERPREF) {
1987 ED_area_tag_redraw(area);
1988 }
1989 }
1990 }
1991 }
1992}
1993
1996/* -------------------------------------------------------------------- */
2004{
2005 if (!keymap) {
2006 return nullptr;
2007 }
2008
2009 /* First user defined keymaps. */
2011 &wm->userconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
2012
2013 if (km) {
2014 return km;
2015 }
2016
2017 return keymap;
2018}
2019
2022/* -------------------------------------------------------------------- */
2029{
2030 if (!keymap) {
2031 return;
2032 }
2033
2034 /* Construct default keymap from preset + addons. */
2035 wmKeyMap *defaultmap = wm_keymap_preset(wm, keymap);
2036 wmKeyMap *addonmap = WM_keymap_list_find(
2037 &wm->addonconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
2038
2039 if (addonmap) {
2040 defaultmap = wm_keymap_copy(defaultmap);
2041 wm_keymap_addon_add(defaultmap, addonmap);
2042 }
2043
2044 /* Find original item. */
2045 wmKeyMapItem *orig = WM_keymap_item_find_id(defaultmap, kmi->id);
2046
2047 if (orig) {
2048 /* Restore to original. */
2049 if (!STREQ(orig->idname, kmi->idname)) {
2050 STRNCPY(kmi->idname, orig->idname);
2051 WM_keymap_item_properties_reset(kmi, nullptr);
2052 }
2053
2054 if (orig->properties) {
2055 if (kmi->properties) {
2057 kmi->properties = nullptr;
2058 }
2059
2061 if (kmi->ptr) {
2062 kmi->ptr->data = kmi->properties;
2063 }
2064 }
2065
2066 kmi->propvalue = orig->propvalue;
2067 kmi->type = orig->type;
2068 kmi->val = orig->val;
2069 kmi->shift = orig->shift;
2070 kmi->ctrl = orig->ctrl;
2071 kmi->alt = orig->alt;
2072 kmi->oskey = orig->oskey;
2073 kmi->keymodifier = orig->keymodifier;
2074 kmi->maptype = orig->maptype;
2075 kmi->flag = (kmi->flag & ~(KMI_REPEAT_IGNORE | KMI_INACTIVE)) |
2076 (orig->flag & (KMI_REPEAT_IGNORE | KMI_INACTIVE));
2077
2078 WM_keyconfig_update_tag(keymap, kmi);
2079 }
2080
2081 /* Free temporary keymap. */
2082 if (addonmap) {
2083 WM_keymap_clear(defaultmap);
2084 MEM_freeN(defaultmap);
2085 }
2086}
2087
2089{
2090 /* Remove keymap from U.user_keymaps and update. */
2091 wmKeyMap *usermap = WM_keymap_list_find(
2092 &U.user_keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
2093
2094 if (usermap) {
2095 WM_keymap_clear(usermap);
2096 BLI_freelinkN(&U.user_keymaps, usermap);
2097
2098 WM_keyconfig_update_tag(nullptr, nullptr);
2100 }
2101}
2102
2104{
2105 LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
2106 if (kmi->id == id) {
2107 return kmi;
2108 }
2109 }
2110
2111 return nullptr;
2112}
2113
2114const char *WM_bool_as_string(bool test)
2115{
2116 return test ? IFACE_("ON") : IFACE_("OFF");
2117}
2118
WorkSpace * CTX_wm_workspace(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define G_MAIN
@ G_DEBUG_WM
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1227
bool IDP_EqualsProperties_ex(const IDProperty *prop1, const IDProperty *prop2, bool is_strict) ATTR_WARN_UNUSED_RESULT
Definition idprop.cc:893
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:861
void IDP_print(const IDProperty *prop)
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
bool BKE_workspace_owner_id_check(const WorkSpace *workspace, const char *owner_id) ATTR_NONNULL()
Definition workspace.cc:536
bool BLF_has_glyph(int fontid, unsigned int unicode) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:155
int BLF_default()
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
#define STRNCPY(dst, src)
Definition BLI_string.h:593
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define STRNCPY_UTF8(dst, src)
unsigned int BLI_str_utf8_as_unicode_or_error(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define BLI_STR_UTF8_BROKEN_CIRCLE_WITH_NORTHWEST_ARROW
#define BLI_STR_UTF8_LEFTWARDS_ARROW
#define BLI_STR_UTF8_BLACK_DIAMOND_MINUS_WHITE_X
#define BLI_STR_UTF8_UPWARDS_WHITE_ARROW
#define BLI_STR_UTF8_UPWARDS_ARROW
#define BLI_STR_UTF8_DOWNWARDS_ARROW
#define BLI_STR_UTF8_OPEN_BOX
#define BLI_STR_UTF8_PLACE_OF_INTEREST_SIGN
#define BLI_STR_UTF8_UP_ARROWHEAD
#define BLI_STR_UTF8_HORIZONTAL_TAB_KEY
#define BLI_STR_UTF8_RIGHTWARDS_ARROW
#define BLI_STR_UTF8_ERASE_TO_THE_LEFT
#define BLI_STR_UTF8_RETURN_SYMBOL
#define BLI_STR_UTF8_OPTION_KEY
#define ARRAY_SIZE(arr)
#define STREQLEN(a, b, n)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define LIKELY(x)
#define BLT_I18NCONTEXT_ID_WINDOWMANAGER
#define CTX_N_(context, msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_UI_EVENTS
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
Object is a sort of wrapper for general info.
@ RGN_TYPE_CHANNELS
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
@ SPACE_USERPREF
@ SPACE_EMPTY
@ USER_SECTION_KEYMAP
#define KMAP_MAX_NAME
@ KEYMAP_USER_MODIFIED
@ KEYMAP_CHILDREN_EXPANDED
@ WM_INIT_FLAG_KEYCONFIG
#define WM_KEYCONFIG_ARRAY_P(wm)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
Read Guarded memory(de)allocation.
@ RNA_EQ_UNSET_MATCH_NONE
std::optional< std::string > UI_key_event_operator_string(const bContext *C, const char *opname, IDProperty *properties, bool is_strict)
@ OPTYPE_MACRO
Definition WM_types.hh:165
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_ANY
Definition WM_types.hh:282
@ KM_PRESS
Definition WM_types.hh:284
@ KM_CLICK_DRAG
Definition WM_types.hh:292
@ KM_DBL_CLICK
Definition WM_types.hh:287
@ KM_RELEASE
Definition WM_types.hh:285
@ KM_CLICK
Definition WM_types.hh:286
wmOperatorCallContext
Definition WM_types.hh:216
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
@ WM_OP_EXEC_REGION_WIN
Definition WM_types.hh:226
@ WM_OP_EXEC_REGION_PREVIEW
Definition WM_types.hh:228
@ WM_OP_INVOKE_REGION_PREVIEW
Definition WM_types.hh:221
@ WM_OP_EXEC_REGION_CHANNELS
Definition WM_types.hh:227
@ WM_OP_INVOKE_REGION_CHANNELS
Definition WM_types.hh:220
@ KM_CTRL
Definition WM_types.hh:256
@ KM_ALT
Definition WM_types.hh:257
@ KM_ALT_ANY
Definition WM_types.hh:264
@ KM_OSKEY_ANY
Definition WM_types.hh:265
@ KM_SHIFT_ANY
Definition WM_types.hh:262
@ KM_OSKEY
Definition WM_types.hh:259
@ KM_CTRL_ANY
Definition WM_types.hh:263
@ KM_SHIFT
Definition WM_types.hh:255
@ KM_TEXTINPUT
Definition WM_types.hh:277
CLG_LogRef * WM_LOG_KEYMAPS
#define KM_MOD_HELD
Definition WM_types.hh:270
unsigned int U
Definition btGjkEpa3.h:78
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
local_group_size(16, 16) .push_constant(Type b
#define printf
#define offsetof(t, d)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define G(x, y, z)
static void update(bNodeTree *ntree)
bool RNA_enum_value_from_id(const EnumPropertyItem *item, const char *identifier, int *r_value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_struct_state_owner_get()
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
const EnumPropertyItem rna_enum_event_type_items[]
Definition rna_wm.cc:206
signed char int8_t
Definition stdint.h:75
void * first
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
struct wmKeyMapDiffItem * next
struct wmKeyMapDiffItem * prev
bool(* filter_fn)(const wmKeyMap *km, const wmKeyMapItem *kmi, void *user_data)
Definition wm_keymap.cc:52
struct PointerRNA * ptr
struct wmKeyMapItem * next
struct wmKeyMapItem * prev
bool(* poll_modal_item)(const struct wmOperator *op, int value)
bool(* poll)(struct bContext *)
const void * modal_items
wmKeyMap * modalkeymap
Definition WM_types.hh:1098
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct wmKeyConfig * defaultconf
struct wmKeyConfig * userconf
struct wmKeyConfig * addonconf
void WM_dropbox_update_ot()
int WM_userdef_event_map(int kmitype)
bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask)
void WM_event_get_keymaps_from_handler(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
@ WM_HANDLER_TYPE_KEYMAP
eEventType_Mask
#define ISTIMER(event_type)
#define IS_EVENT_ACTIONZONE(event_type)
#define ISKEYBOARD(event_type)
@ EVT_RIGHTCTRLKEY
@ EVT_TABKEY
@ EVT_DOWNARROWKEY
@ EVT_OSKEY
@ EVT_LEFTCTRLKEY
@ TABLET_ERASER
@ EVT_RIGHTARROWKEY
@ EVT_SPACEKEY
@ TABLET_STYLUS
@ EVT_RIGHTALTKEY
@ EVT_UPARROWKEY
@ EVT_LEFTARROWKEY
@ EVT_LEFTALTKEY
@ EVT_ESCKEY
@ EVT_BACKSPACEKEY
@ EVT_RIGHTSHIFTKEY
@ EVT_LEFTSHIFTKEY
@ EVT_RETKEY
#define EVT_TYPE_MASK_ALL
#define ISNDOF(event_type)
#define ISMOUSE(event_type)
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_keyconfig_clear(wmKeyConfig *keyconf)
Definition wm_keymap.cc:350
static char wm_keymap_update_flag
static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
Definition wm_keymap.cc:535
static int8_t wm_keymap_update_suppress_count
std::optional< std::string > WM_modalkeymap_operator_items_to_string(wmOperatorType *ot, const int propvalue, const bool compact)
static wmKeyMap * wm_keymap_copy(wmKeyMap *keymap)
Definition wm_keymap.cc:422
wmKeyConfig * WM_keyconfig_new(wmWindowManager *wm, const char *idname, bool user_defined)
Definition wm_keymap.cc:289
void WM_keymap_item_restore_to_default(wmWindowManager *wm, wmKeyMap *keymap, wmKeyMapItem *kmi)
wmKeyMapItem * WM_key_event_operator(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const short include_mask, const short exclude_mask, wmKeyMap **r_keymap)
void WM_keymap_restore_to_default(wmKeyMap *keymap, wmWindowManager *wm)
static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi, const bool keep_properties)
Definition wm_keymap.cc:126
static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
Definition wm_keymap.cc:113
wmKeyMapItem * WM_keymap_add_item_copy(wmKeyMap *keymap, wmKeyMapItem *kmi_src)
Definition wm_keymap.cc:566
static wmKeyMap * wm_keymap_patch_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *addonmap, wmKeyMap *usermap)
Definition wm_keymap.cc:747
wmKeyMap * WM_keymap_find_all_spaceid_or_empty(wmWindowManager *wm, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:916
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
@ WM_KEYMAP_UPDATE_POSTPONE
@ WM_KEYMAP_UPDATE_RECONFIGURE
@ WM_KEYMAP_UPDATE_OPERATORTYPE
wmKeyMap * WM_keymap_list_find_spaceid_or_empty(ListBase *lb, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:881
wmKeyMapItem * WM_key_event_operator_from_keymap(wmKeyMap *keymap, const char *opname, IDProperty *properties, const short include_mask, const short exclude_mask)
void WM_keyconfig_update(wmWindowManager *wm)
static wmKeyMapItem * wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *needle)
Definition wm_keymap.cc:614
wmKeyMapItem * WM_keymap_item_find_id(wmKeyMap *keymap, int id)
static wmKeyMapItem * wm_keymap_item_find_props(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict, const wmKeyMapItemFind_Params *params, wmKeyMap **r_keymap)
wmKeyMapItem * WM_modalkeymap_add_item(wmKeyMap *km, const KeyMapItem_Params *params, int value)
Definition wm_keymap.cc:973
void WM_keymap_item_properties_reset(wmKeyMapItem *kmi, IDProperty *properties)
Definition wm_keymap.cc:204
void WM_keyconfig_update_ex(wmWindowManager *wm, bool keep_properties)
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
void WM_keymap_clear(wmKeyMap *keymap)
Definition wm_keymap.cc:445
static void wm_keymap_addon_add(wmKeyMap *keymap, wmKeyMap *addonmap)
Definition wm_keymap.cc:605
std::optional< std::string > WM_key_event_operator_string(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict)
static wmKeyMapItem * wm_keymap_item_copy(wmKeyMapItem *kmi)
Definition wm_keymap.cc:62
const wmKeyMapItem * WM_modalkeymap_find_propvalue(const wmKeyMap *km, const int propvalue)
wmKeyMap * WM_keymap_find_all(wmWindowManager *wm, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:911
static wmKeyMap * wm_keymap_preset(wmWindowManager *wm, wmKeyMap *km)
static wmKeyMapItem * wm_keymap_item_find_handlers(const bContext *C, wmWindowManager *wm, wmWindow *win, ListBase *handlers, const char *opname, wmOperatorCallContext, IDProperty *properties, const bool is_strict, const wmKeyMapItemFind_Params *params, wmKeyMap **r_keymap)
static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km)
Definition wm_keymap.cc:684
static const char * key_event_glyph_or_text(const int font_id, const char *text, const char *single_glyph)
static wmKeyConfig * WM_keyconfig_active(wmWindowManager *wm)
Definition wm_keymap.cc:366
wmKeyConfig * WM_keyconfig_ensure(wmWindowManager *wm, const char *idname, bool user_defined)
Definition wm_keymap.cc:305
static bool wm_keymap_test_and_clear_update(wmKeyMap *km)
std::optional< std::string > WM_keymap_item_raw_to_string(const short shift, const short ctrl, const short alt, const short oskey, const short keymodifier, const short val, const short type, const bool compact)
int WM_keymap_item_map_type_get(const wmKeyMapItem *kmi)
Definition wm_keymap.cc:221
static void wm_keymap_diff_item_free(wmKeyMapDiffItem *kmdi)
Definition wm_keymap.cc:267
void WM_keyconfig_update_operatortype()
void WM_keyconfig_free(wmKeyConfig *keyconf)
Definition wm_keymap.cc:360
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
Definition wm_keymap.cc:469
void WM_keyconfig_update_suppress_begin()
wmKeyMap * WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *addonmap, wmKeyMap *km)
Definition wm_keymap.cc:813
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:960
void WM_keyconfig_update_postpone_end()
std::optional< std::string > WM_modalkeymap_items_to_string(const wmKeyMap *km, const int propvalue, const bool compact)
static wmKeyMapItem * wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapItem *needle)
Definition wm_keymap.cc:625
void WM_keyconfig_update_suppress_end()
static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km, const wmKeyMapItem *kmi, void *user_data)
wmKeyMapItem * WM_keymap_add_item(wmKeyMap *keymap, const char *idname, const KeyMapItem_Params *params)
Definition wm_keymap.cc:546
static bool kmi_filter_is_visible(const wmKeyMap *, const wmKeyMapItem *kmi, void *)
static void wm_keymap_item_clear_runtime(wmKeyMapItem *kmi)
Definition wm_keymap.cc:102
std::optional< std::string > WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact)
void WM_keyconfig_update_postpone_begin()
void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname)
Definition wm_keymap.cc:381
const char * WM_bool_as_string(bool test)
static void wm_keymap_item_free_data(wmKeyMapItem *kmi)
Definition wm_keymap.cc:87
void WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
Definition wm_keymap.cc:461
static wmKeyMap * wm_keymap_new(const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:405
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:897
static char wm_keymap_update_suppress_flag
static const wmKeyMapItem * wm_modalkeymap_find_propvalue_iter(const wmKeyMap *km, const wmKeyMapItem *kmi, const int propvalue)
static wmKeyMapDiffItem * wm_keymap_diff_item_copy(wmKeyMapDiffItem *kmdi)
Definition wm_keymap.cc:252
static wmKeyMapItem * wm_keymap_item_find(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, bool is_strict, const wmKeyMapItemFind_Params *params, wmKeyMap **r_keymap)
static void wm_keymap_diff(wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km, wmKeyMap *orig_km, wmKeyMap *addon_km)
Definition wm_keymap.cc:636
const char * WM_key_event_string(const short type, const bool compact)
wmKeyMap * WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:868
static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
Definition wm_keymap.cc:194
static wmKeyMapItem * wm_keymap_item_find_in_keymap(wmKeyMap *keymap, const char *opname, IDProperty *properties, const bool is_strict, const wmKeyMapItemFind_Params *params)
wmKeyMapItem * WM_modalkeymap_add_item_str(wmKeyMap *km, const KeyMapItem_Params *params, const char *value)
Definition wm_keymap.cc:990
void WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
Definition wm_keymap.cc:328
void WM_keyconfig_update_tag(wmKeyMap *keymap, wmKeyMapItem *kmi)
void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
Definition wm_keymap.cc:579
bool WM_keymap_item_compare(const wmKeyMapItem *k1, const wmKeyMapItem *k2)
static bool wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
Definition wm_keymap.cc:186
static void keymap_event_set(wmKeyMapItem *kmi, const KeyMapItem_Params *params)
Definition wm_keymap.cc:503
static void wm_keymap_item_properties_update_ot_from_list(ListBase *km_lb, const bool keep_properties)
Definition wm_keymap.cc:167
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
bScreen * WM_window_get_active_screen(const wmWindow *win)