4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2007 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
31 #include "DNA_screen_types.h"
32 #include "DNA_userdef_types.h"
33 #include "DNA_windowmanager_types.h"
35 #include "MEM_guardedalloc.h"
37 #include "BLI_blenlib.h"
39 #include "BKE_blender.h"
40 #include "BKE_context.h"
41 #include "BKE_idprop.h"
42 #include "BKE_library.h"
44 #include "BKE_utildefines.h"
46 #include "RNA_access.h"
47 #include "RNA_types.h"
48 #include "RNA_enum_types.h"
52 #include "wm_window.h"
53 #include "wm_event_system.h"
54 #include "wm_event_types.h"
56 /* ********************* key config ***********************/
58 void WM_keymap_properties_reset(wmKeyMapItem *kmi)
60 WM_operator_properties_free(kmi->ptr);
64 kmi->properties = NULL;
66 WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
69 static void keymap_properties_set(wmKeyMapItem *kmi)
71 WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
74 wmKeyConfig *WM_keyconfig_add(wmWindowManager *wm, char *idname)
78 keyconf= MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig");
79 BLI_strncpy(keyconf->idname, idname, sizeof(keyconf->idname));
80 BLI_addtail(&wm->keyconfigs, keyconf);
85 void WM_keyconfig_free(wmKeyConfig *keyconf)
89 while((km= keyconf->keymaps.first)) {
91 BLI_freelinkN(&keyconf->keymaps, km);
97 void WM_keyconfig_userdef(wmWindowManager *wm)
102 for(km=U.keymaps.first; km; km=km->next) {
103 /* modal keymaps don't have operator properties */
104 if ((km->flag & KEYMAP_MODAL) == 0) {
105 for(kmi=km->items.first; kmi; kmi=kmi->next) {
106 keymap_properties_set(kmi);
112 static wmKeyConfig *wm_keyconfig_list_find(ListBase *lb, char *idname)
116 for(kc= lb->first; kc; kc= kc->next)
117 if(0==strncmp(idname, kc->idname, KMAP_MAX_NAME))
123 /* ************************ free ************************* */
125 void WM_keymap_free(wmKeyMap *keymap)
129 for(kmi=keymap->items.first; kmi; kmi=kmi->next) {
131 WM_operator_properties_free(kmi->ptr);
136 BLI_freelistN(&keymap->items);
139 /* ***************** generic call, exported **************** */
141 static void keymap_event_set(wmKeyMapItem *kmi, short type, short val, int modifier, short keymodifier)
145 kmi->keymodifier= keymodifier;
147 if(modifier == KM_ANY) {
148 kmi->shift= kmi->ctrl= kmi->alt= kmi->oskey= KM_ANY;
152 kmi->shift= kmi->ctrl= kmi->alt= kmi->oskey= 0;
155 if(modifier & KM_SHIFT)
157 else if(modifier & KM_SHIFT2)
159 if(modifier & KM_CTRL)
161 else if(modifier & KM_CTRL2)
163 if(modifier & KM_ALT)
165 else if(modifier & KM_ALT2)
167 if(modifier & KM_OSKEY)
169 else if(modifier & KM_OSKEY2)
174 /* if item was added, then bail out */
175 wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, int type, int val, int modifier, int keymodifier)
179 for(kmi= keymap->items.first; kmi; kmi= kmi->next)
180 if(strncmp(kmi->idname, idname, OP_MAX_TYPENAME)==0)
183 kmi= MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
185 BLI_addtail(&keymap->items, kmi);
186 BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
188 keymap_event_set(kmi, type, val, modifier, keymodifier);
189 keymap_properties_set(kmi);
194 /* always add item */
195 wmKeyMapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, int type, int val, int modifier, int keymodifier)
197 wmKeyMapItem *kmi= MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
199 BLI_addtail(&keymap->items, kmi);
200 BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
202 keymap_event_set(kmi, type, val, modifier, keymodifier);
203 keymap_properties_set(kmi);
205 if ((keymap->flag & KEYMAP_USER) == 0) {
207 kmi->id = keymap->kmi_id;
213 /* menu wrapper for WM_keymap_add_item */
214 wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, char *idname, int type, int val, int modifier, int keymodifier)
216 wmKeyMapItem *kmi= WM_keymap_add_item(keymap, "WM_OT_call_menu", type, val, modifier, keymodifier);
217 RNA_string_set(kmi->ptr, "name", idname);
221 void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
223 if(BLI_findindex(&keymap->items, kmi) != -1) {
225 WM_operator_properties_free(kmi->ptr);
228 BLI_freelinkN(&keymap->items, kmi);
232 /* ****************** storage in WM ************ */
234 /* name id's are for storing general or multiple keymaps,
235 space/region ids are same as DNA_space_types.h */
236 /* gets free'd in wm.c */
238 wmKeyMap *WM_keymap_list_find(ListBase *lb, char *idname, int spaceid, int regionid)
242 for(km= lb->first; km; km= km->next)
243 if(km->spaceid==spaceid && km->regionid==regionid)
244 if(0==strncmp(idname, km->idname, KMAP_MAX_NAME))
250 wmKeyMap *WM_keymap_find(wmKeyConfig *keyconf, char *idname, int spaceid, int regionid)
252 wmKeyMap *km= WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
255 km= MEM_callocN(sizeof(struct wmKeyMap), "keymap list");
256 BLI_strncpy(km->idname, idname, KMAP_MAX_NAME);
257 km->spaceid= spaceid;
258 km->regionid= regionid;
259 BLI_addtail(&keyconf->keymaps, km);
265 /* ****************** modal keymaps ************ */
267 /* modal maps get linked to a running operator, and filter the keys before sending to modal() callback */
269 wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, char *idname, EnumPropertyItem *items)
271 wmKeyMap *km= WM_keymap_find(keyconf, idname, 0, 0);
272 km->flag |= KEYMAP_MODAL;
273 km->modal_items= items;
278 wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, char *idname)
282 for(km= keyconf->keymaps.first; km; km= km->next)
283 if(km->flag & KEYMAP_MODAL)
284 if(0==strncmp(idname, km->idname, KMAP_MAX_NAME))
291 wmKeyMapItem *WM_modalkeymap_add_item(wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value)
293 wmKeyMapItem *kmi= MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
295 BLI_addtail(&km->items, kmi);
296 kmi->propvalue= value;
298 keymap_event_set(kmi, type, val, modifier, keymodifier);
300 if ((km->flag & KEYMAP_USER) == 0) {
302 kmi->id = km->kmi_id;
308 void WM_modalkeymap_assign(wmKeyMap *km, char *opname)
310 wmOperatorType *ot= WM_operatortype_find(opname, 0);
315 printf("error: modalkeymap_assign, unknown operator %s\n", opname);
318 /* ***************** get string from key events **************** */
320 const char *WM_key_event_string(short type)
322 const char *name= NULL;
323 if(RNA_enum_name(event_type_items, (int)type, &name))
329 char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len)
335 if (kmi->shift == KM_ANY &&
336 kmi->ctrl == KM_ANY &&
337 kmi->alt == KM_ANY &&
338 kmi->oskey == KM_ANY) {
343 strcat(buf, "Shift ");
346 strcat(buf, "Ctrl ");
355 if(kmi->keymodifier) {
356 strcat(buf, WM_key_event_string(kmi->keymodifier));
360 strcat(buf, WM_key_event_string(kmi->type));
361 BLI_strncpy(str, buf, len);
366 static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *handlers, const char *opname, int opcontext, IDProperty *properties, int compare_props, wmKeyMap **keymap_r)
368 wmWindowManager *wm= CTX_wm_manager(C);
369 wmEventHandler *handler;
373 /* find keymap item in handlers */
374 for(handler=handlers->first; handler; handler=handler->next) {
375 keymap= WM_keymap_active(wm, handler->keymap);
377 if(keymap && (!keymap->poll || keymap->poll((bContext*)C))) {
378 for(kmi=keymap->items.first; kmi; kmi=kmi->next) {
379 if(strcmp(kmi->idname, opname) == 0 && WM_key_event_string(kmi->type)[0]) {
381 if(kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data)) {
382 if(keymap_r) *keymap_r= keymap;
387 if(keymap_r) *keymap_r= keymap;
398 static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, const char *opname, int opcontext, IDProperty *properties, int compare_props, wmKeyMap **keymap_r)
400 wmWindow *win= CTX_wm_window(C);
401 ScrArea *sa= CTX_wm_area(C);
402 ARegion *ar= CTX_wm_region(C);
403 wmKeyMapItem *found= NULL;
405 /* look into multiple handler lists to find the item */
407 found= wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, compare_props, keymap_r);
410 if(sa && found==NULL)
411 found= wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, compare_props, keymap_r);
414 if(ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
416 ARegion *ar= sa->regionbase.first;
417 for(; ar; ar= ar->next)
418 if(ar->regiontype==RGN_TYPE_WINDOW)
422 found= wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, keymap_r);
427 found= wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, keymap_r);
434 static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const char *opname, int opcontext, IDProperty *properties, wmKeyMap **keymap_r)
436 wmKeyMapItem *found= wm_keymap_item_find_props(C, opname, opcontext, properties, 1, keymap_r);
439 found= wm_keymap_item_find_props(C, opname, opcontext, properties, 0, keymap_r);
444 char *WM_key_event_operator_string(const bContext *C, const char *opname, int opcontext, IDProperty *properties, char *str, int len)
446 wmKeyMapItem *kmi= wm_keymap_item_find(C, opname, opcontext, properties, NULL);
449 WM_keymap_item_to_string(kmi, str, len);
456 /* ***************** user preferences ******************* */
458 int WM_keymap_user_init(wmWindowManager *wm, wmKeyMap *keymap)
460 wmKeyConfig *keyconf;
466 /* init from user key config */
467 keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
469 km= WM_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
471 keymap->poll= km->poll; /* lazy init */
472 keymap->modal_items= km->modal_items;
477 /* or from default */
478 km= WM_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
480 keymap->poll= km->poll; /* lazy init */
481 keymap->modal_items= km->modal_items;
488 wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap)
490 wmKeyConfig *keyconf;
496 /* first user defined keymaps */
497 km= WM_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
499 km->poll= keymap->poll; /* lazy init */
500 km->modal_items= keymap->modal_items;
504 /* then user key config */
505 keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
507 km= WM_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
509 km->poll= keymap->poll; /* lazy init */
510 km->modal_items= keymap->modal_items;
515 /* then use default */
516 km= WM_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
520 wmKeyMap *WM_keymap_copy_to_user(wmKeyMap *keymap)
525 usermap= WM_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
528 /* not saved yet, duplicate existing */
529 usermap= MEM_dupallocN(keymap);
530 usermap->modal_items= NULL;
532 usermap->flag |= KEYMAP_USER;
534 BLI_addtail(&U.keymaps, usermap);
537 /* already saved, free items for re-copy */
538 WM_keymap_free(usermap);
541 BLI_duplicatelist(&usermap->items, &keymap->items);
543 for(kmi=usermap->items.first; kmi; kmi=kmi->next) {
544 if(kmi->properties) {
545 kmi->ptr= MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr");
546 WM_operator_properties_create(kmi->ptr, kmi->idname);
548 kmi->properties= IDP_CopyProperty(kmi->properties);
549 kmi->ptr->data= kmi->properties;
553 for(kmi=keymap->items.first; kmi; kmi=kmi->next)
554 kmi->flag &= ~KMI_EXPANDED;
559 void WM_keymap_restore_item_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapItem *kmi)
561 wmWindowManager *wm = CTX_wm_manager(C);
562 wmKeyConfig *keyconf;
565 /* look in user key config */
566 keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
568 km= WM_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
572 /* or from default */
573 km= WM_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
579 for (orig = km->items.first; orig; orig = orig->next) {
580 if (orig->id == kmi->id)
585 if(strcmp(orig->idname, kmi->idname) != 0) {
586 BLI_strncpy(kmi->idname, orig->idname, sizeof(kmi->idname));
588 WM_keymap_properties_reset(kmi);
590 kmi->properties= IDP_CopyProperty(orig->properties);
591 kmi->ptr->data= kmi->properties;
593 kmi->propvalue = orig->propvalue;
594 kmi->type = orig->type;
595 kmi->val = orig->val;
596 kmi->shift = orig->shift;
597 kmi->ctrl = orig->ctrl;
598 kmi->alt = orig->alt;
599 kmi->oskey = orig->oskey;
600 kmi->keymodifier = orig->keymodifier;
601 kmi->maptype = orig->maptype;
608 void WM_keymap_restore_to_default(wmKeyMap *keymap)
612 usermap= WM_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
615 WM_keymap_free(usermap);
616 BLI_freelinkN(&U.keymaps, usermap);
620 /* searches context and changes keymap item, if found */
621 void WM_key_event_operator_change(const bContext *C, const char *opname, int opcontext, IDProperty *properties, short key, short modifier)
623 wmWindowManager *wm= CTX_wm_manager(C);
627 kmi= wm_keymap_item_find(C, opname, opcontext, properties, &keymap);
630 /* if the existing one is in a default keymap, copy it
631 to user preferences, and lookup again so we get a
632 key map item from the user preferences we can modify */
633 if(BLI_findindex(&wm->defaultconf->keymaps, keymap) >= 0) {
634 WM_keymap_copy_to_user(keymap);
635 kmi= wm_keymap_item_find(C, opname, opcontext, properties, NULL);
638 keymap_event_set(kmi, key, KM_PRESS, modifier, 0);