ShapeKey Editor (sub-mode of DopeSheet Editor)
authorJoshua Leung <aligorith@gmail.com>
Fri, 16 Oct 2009 12:08:47 +0000 (12:08 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 16 Oct 2009 12:08:47 +0000 (12:08 +0000)
Special priority request from Durian team to get this sub-editor of the DopeSheet Editor restored. Originally I was kindof planning to drop it, but obviously it still has a role!

It now supports all the modern features that the DopeSheet supports, complete with selection, muting, locking, DopeSheet summary, and all the other tools that you know and love from the other views.

Also, this no longer uses the old hacky sliders that 2.4x used (instead it uses RNA-based ones), so should function just the same as other DopeSheet views).

source/blender/blenkernel/BKE_key.h
source/blender/blenkernel/intern/key.c
source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_filter.c
source/blender/editors/include/ED_anim_api.h
source/blender/makesdna/DNA_key_types.h

index 4bfa6a41099d5c1e51beeb4e9008c82bb3768bd1..1b4cbc1cf2a6dba0e2bc480e3965b22586f22c14 100644 (file)
@@ -65,6 +65,7 @@ struct Key *ob_get_key(struct Object *ob);
 struct KeyBlock *ob_get_keyblock(struct Object *ob);
 struct KeyBlock *key_get_keyblock(struct Key *key, int index);
 struct KeyBlock *key_get_named_keyblock(struct Key *key, const char name[]);
+char *key_get_curValue_rnaPath(struct Key *key, struct KeyBlock *kb);
 // needed for the GE
 void do_rel_key(int start, int end, int tot, char *basispoin, struct Key *key, int mode);
 
index b6e4ffd6cc3861f7f501c4685893e02ad8c1af8c..3fffdef478bf81464d03a2ff1b9164e10f83ca3a 100644 (file)
@@ -35,6 +35,8 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "BLI_blenlib.h"
+
 #include "DNA_anim_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_key_types.h"
@@ -57,7 +59,7 @@
 #include "BKE_object.h"
 #include "BKE_utildefines.h"
 
-#include "BLI_blenlib.h"
+#include "RNA_access.h"
 
 
 #ifdef HAVE_CONFIG_H
@@ -1489,3 +1491,24 @@ KeyBlock *key_get_named_keyblock(Key *key, const char name[])
        
        return NULL;
 }
+
+/* Get RNA-Path for 'value' setting of the given ShapeKey 
+ * NOTE: the user needs to free the returned string once they're finishe with it
+ */
+char *key_get_curValue_rnaPath(Key *key, KeyBlock *kb)
+{
+       PointerRNA ptr;
+       PropertyRNA *prop;
+       
+       /* sanity checks */
+       if ELEM(NULL, key, kb)
+               return NULL;
+       
+       /* create the RNA pointer */
+       RNA_pointer_create(key, &RNA_ShapeKey, kb, &ptr);
+       /* get pointer to the property too */
+       prop= RNA_struct_find_property(&ptr, "value");
+       
+       /* return the path */
+       return RNA_path_from_ID_to_property(&ptr, prop);
+}
index 7c9814eda7b346216ad8afda6691b77e2740de72..2cd41b0ffb7163dfb1b27ef59536067933a2ecaf 100644 (file)
@@ -1386,7 +1386,7 @@ static int acf_dsskey_setting_flag(int setting, short *neg)
        
        switch (setting) {
                case ACHANNEL_SETTING_EXPAND: /* expanded */
-                       return KEYBLOCK_DS_EXPAND;
+                       return KEY_DS_EXPAND;
                        
                case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
                        return ADT_NLA_EVAL_OFF;
@@ -1737,28 +1737,91 @@ static bAnimChannelType ACF_DSARM=
 
 
 /* ShapeKey Entry  ------------------------------------------- */
-// XXX ... this is currently obsolete...
 
-#if 0
-static void dummy_olddraw_shapekeys ()
+/* name for ShapeKey */
+static void acf_shapekey_name(bAnimListElem *ale, char *name)
 {
-       case ANIMTYPE_SHAPEKEY: /* shapekey channel */
-       {
-               KeyBlock *kb = (KeyBlock *)ale->data;
+       KeyBlock *kb= (KeyBlock *)ale->data;
+       
+       /* just copy the name... */
+       if (kb && name) {
+               /* if the KeyBlock had a name, use it, otherwise use the index */
+               if (kb->name[0])
+                       strcpy(name, kb->name);
+               else
+                       sprintf(name, "Key %d", ale->index);
+       }
+}
+
+/* check if some setting exists for this channel */
+static short acf_shapekey_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting)
+{
+       switch (setting) {
+               case ACHANNEL_SETTING_SELECT: /* selected */
+               case ACHANNEL_SETTING_MUTE: /* muted */
+               case ACHANNEL_SETTING_PROTECT: /* protected */
+                       return 1;
+                       
+               /* nothing else is supported */
+               default:
+                       return 0;
+       }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid  */
+static int acf_shapekey_setting_flag(int setting, short *neg)
+{
+       /* clear extra return data first */
+       *neg= 0;
+       
+       switch (setting) {
+               case ACHANNEL_SETTING_MUTE: /* mute */
+                       return KEYBLOCK_MUTE;
                
-               indent = 0;
-               special = -1;
+               case ACHANNEL_SETTING_SELECT: /* selected */
+                       return KEYBLOCK_SEL;
                
-               offset= (ale->id) ? 21 : 0;
+               case ACHANNEL_SETTING_PROTECT: /* locked */
+                       return KEYBLOCK_LOCKED;
                
-               if (kb->name[0] == '\0')
-                       sprintf(name, "Key %d", ale->index);
-               else
-                       strcpy(name, kb->name);
+               default: /* unsupported */
+                       return 0;
        }
-               break;
 }
-#endif
+
+/* get pointer to the setting */
+static void *acf_shapekey_setting_ptr(bAnimListElem *ale, int setting, short *type)
+{
+       KeyBlock *kb= (KeyBlock *)ale->data;
+       
+       /* clear extra return data first */
+       *type= 0;
+       
+       switch (setting) {
+               case ACHANNEL_SETTING_SELECT: /* selected */
+               case ACHANNEL_SETTING_MUTE: /* muted */
+               case ACHANNEL_SETTING_PROTECT: /* protected */
+                       GET_ACF_FLAG_PTR(kb->flag)
+               
+               default: /* unsupported */
+                       return NULL;
+       }
+}
+
+/* shapekey expander type define */
+static bAnimChannelType ACF_SHAPEKEY= 
+{
+       acf_generic_channel_backdrop,   /* backdrop */
+       acf_generic_indention_0,                /* indent level */
+       acf_generic_basic_offset,               /* offset */
+       
+       acf_shapekey_name,                              /* name */
+       NULL,                                                   /* icon */
+       
+       acf_shapekey_setting_valid,             /* has setting */
+       acf_shapekey_setting_flag,              /* flag for setting */
+       acf_shapekey_setting_ptr                /* pointer for setting */
+};
 
 /* Grease Pencil entries  ------------------------------------------- */
 // XXX ... this is currently not restored yet
@@ -1923,7 +1986,7 @@ void ANIM_init_channel_typeinfo_data (void)
                animchannelTypeInfo[type++]= &ACF_DSMBALL;              /* MetaBall Channel */
                animchannelTypeInfo[type++]= &ACF_DSARM;                /* Armature Channel */
                
-               animchannelTypeInfo[type++]= NULL;                              /* ShapeKey */ // XXX this is no longer used for now...
+               animchannelTypeInfo[type++]= &ACF_SHAPEKEY;             /* ShapeKey */
                
                        // XXX not restored yet
                animchannelTypeInfo[type++]= NULL;                              /* Grease Pencil Datablock */ 
@@ -2237,7 +2300,57 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
        }
 }
 
-
+/* callback for shapekey widget sliders - insert keyframes */
+static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, void *kb_poin)
+{
+       Key *key= (Key *)key_poin;
+       KeyBlock *kb= (KeyBlock *)kb_poin;
+       char *rna_path= key_get_curValue_rnaPath(key, kb);
+       
+       Scene *scene= CTX_data_scene(C);
+       PointerRNA id_ptr, ptr;
+       PropertyRNA *prop;
+       short flag=0, done=0;
+       float cfra;
+       
+       /* get current frame */
+       // NOTE: this will do for now...
+       cfra= (float)CFRA;
+       
+       /* get flags for keyframing */
+       if (IS_AUTOKEY_FLAG(INSERTNEEDED))
+               flag |= INSERTKEY_NEEDED;
+       if (IS_AUTOKEY_FLAG(AUTOMATKEY))
+               flag |= INSERTKEY_MATRIX;
+       if (IS_AUTOKEY_MODE(scene, EDITKEYS))
+               flag |= INSERTKEY_REPLACE;
+       
+       
+       /* get RNA pointer, and resolve the path */
+       RNA_id_pointer_create((ID *)key, &id_ptr);
+       
+       /* try to resolve the path stored in the F-Curve */
+       if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop)) {
+               /* find or create new F-Curve */
+               // XXX is the group name for this ok?
+               bAction *act= verify_adt_action((ID *)key, 1);
+               FCurve *fcu= verify_fcurve(act, NULL, rna_path, 0, 1);
+               
+               /* set the special 'replace' flag if on a keyframe */
+               if (fcurve_frame_has_keyframe(fcu, cfra, 0))
+                       flag |= INSERTKEY_REPLACE;
+               
+               /* insert a keyframe for this F-Curve */
+               done= insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
+               
+               if (done)
+                       WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
+       }
+       
+       /* free the path */
+       if (rna_path)
+               MEM_freeN(rna_path);
+}
 
 /* Draw a widget for some setting */
 static void draw_setting_widget (bAnimContext *ac, bAnimListElem *ale, bAnimChannelType *acf, uiBlock *block, int xpos, int ypos, int setting)
@@ -2445,7 +2558,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b
                 *        and wouldn't be able to auto-keyframe...
                 *      - slider should start before the toggles (if they're visible) to keep a clean line down the side
                 */
-               if ((draw_sliders) && (ale->type == ANIMTYPE_FCURVE)) {
+               if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) {
                        /* adjust offset */
                        offset += SLIDER_WIDTH;
                        
@@ -2453,20 +2566,49 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b
                        uiBlockSetEmboss(block, UI_EMBOSS);
                        
                        if (ale->id) { /* Slider using RNA Access -------------------- */
-                               FCurve *fcu= (FCurve *)ale->data;
                                PointerRNA id_ptr, ptr;
                                PropertyRNA *prop;
+                               char *rna_path = NULL;
+                               int array_index = 0;
+                               short free_path = 0;
                                
-                               /* get RNA pointer, and resolve the path */
-                               RNA_id_pointer_create(ale->id, &id_ptr);
+                               /* get destination info */
+                               if (ale->type == ANIMTYPE_FCURVE) {
+                                       FCurve *fcu= (FCurve *)ale->data;
+                                       
+                                       rna_path= fcu->rna_path;
+                                       array_index= fcu->array_index;
+                               }
+                               else if (ale->type == ANIMTYPE_SHAPEKEY) {
+                                       KeyBlock *kb= (KeyBlock *)ale->data;
+                                       Key *key= (Key *)ale->id;
+                                       
+                                       rna_path= key_get_curValue_rnaPath(key, kb);
+                                       free_path= 1;
+                               }
                                
-                               /* try to resolve the path */
-                               if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) {
-                                       uiBut *but;
+                               /* only if RNA-Path found */
+                               if (rna_path) {
+                                       /* get RNA pointer, and resolve the path */
+                                       RNA_id_pointer_create(ale->id, &id_ptr);
+                                       
+                                       /* try to resolve the path */
+                                       if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop)) {
+                                               uiBut *but;
+                                               
+                                               /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
+                                               but= uiDefAutoButR(block, &ptr, prop, array_index, "", 0, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc);
+                                               
+                                               /* assign keyframing function according to slider type */
+                                               if (ale->type == ANIMTYPE_SHAPEKEY)
+                                                       uiButSetFunc(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data);
+                                               else
+                                                       uiButSetFunc(but, achannel_setting_slider_cb, ale->id, ale->data);
+                                       }
                                        
-                                       /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */
-                                       but= uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", 0, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc);
-                                       uiButSetFunc(but, achannel_setting_slider_cb, ale->id, fcu);
+                                       /* free the path if necessary */
+                                       if (free_path)
+                                               MEM_freeN(rna_path);
                                }
                        }
                        else { /* Special Slider for stuff without RNA Access ---------- */
index 3b6c7fad47104625f0121b58906fe1c5a95c6a89..efdad53f89f053c576faeffb79da0faad7389036 100644 (file)
@@ -238,6 +238,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                        if (ale->flag & FCURVE_SELECTED)
                                                sel= ACHANNEL_SETFLAG_CLEAR;
                                        break;
+                               case ANIMTYPE_SHAPEKEY:
+                                       if (ale->flag & KEYBLOCK_SEL)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
                                case ANIMTYPE_NLATRACK:
                                        if (ale->flag & NLATRACK_SELECTED)
                                                sel= ACHANNEL_SETFLAG_CLEAR;
@@ -307,6 +311,13 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                fcu->flag &= ~FCURVE_ACTIVE;
                        }
                                break;
+                       case ANIMTYPE_SHAPEKEY:
+                       {
+                               KeyBlock *kb= (KeyBlock *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
+                       }
+                               break;
                        case ANIMTYPE_NLATRACK:
                        {
                                NlaTrack *nlt= (NlaTrack *)ale->data;
@@ -1517,6 +1528,24 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
                        if (fcu->flag & FCURVE_SELECTED)
                                ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
                                
+                       notifierFlags |= ND_ANIMCHAN_SELECT;
+               }
+                       break;
+               case ANIMTYPE_SHAPEKEY: 
+               {
+                       KeyBlock *kb= (KeyBlock *)ale->data;
+                       
+                       /* select/deselect */
+                       if (selectmode == SELECT_INVERT) {
+                               /* inverse selection status of this ShapeKey only */
+                               kb->flag ^= KEYBLOCK_SEL;
+                       }
+                       else {
+                               /* select ShapeKey by itself */
+                               ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               kb->flag |= KEYBLOCK_SEL;
+                       }
+                               
                        notifierFlags |= ND_ANIMCHAN_SELECT;
                }
                        break;
@@ -1557,9 +1586,6 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
 #endif // XXX future of this is unclear
                }
                        break;
-               case ANIMTYPE_SHAPEKEY:
-                       /* TODO: shapekey channels cannot be selected atm... */
-                       break;
                default:
                        printf("Error: Invalid channel type in mouse_anim_channels() \n");
        }
index ea097420d1ac78101e518ab5875513d2e27d5d6b..84da3662661843de7bc327426e21b77247231cb5 100644 (file)
@@ -647,6 +647,36 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s
                                ale->datatype= ALE_FCURVE;
                        }
                                break;
+                               
+                       case ANIMTYPE_SHAPEKEY:
+                       {
+                               KeyBlock *kb= (KeyBlock *)data;
+                               Key *key= (Key *)ale->id;
+                               
+                               ale->flag= kb->flag;
+                               
+                               /* whether we have keyframes depends on whether there is a Key block to find it from */
+                               if (key) {
+                                       /* index of shapekey is defined by place in key's list */
+                                       ale->index= BLI_findindex(&key->block, kb);
+                                       
+                                       /* the corresponding keyframes are from the animdata */
+                                       if (ale->adt && ale->adt->action) {
+                                               bAction *act= ale->adt->action;
+                                               char *rna_path = key_get_curValue_rnaPath(key, kb);
+                                               
+                                               /* try to find the F-Curve which corresponds to this exactly,
+                                                * then free the MEM_alloc'd string
+                                                */
+                                               if (rna_path) {
+                                                       ale->key_data= list_find_fcurve(&act->curves, rna_path, 0);
+                                                       MEM_freeN(rna_path);
+                                               }
+                                       }
+                                       ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE;
+                               }
+                       }       
+                               break;
                        
                        case ANIMTYPE_GPLAYER:
                        {
@@ -892,7 +922,51 @@ static int animdata_filter_nla (ListBase *anim_data, bDopeSheet *ads, AnimData *
        /* return the number of items added to the list */
        return items;
 }
+
+/* Include ShapeKey Data for ShapeKey Editor */
+static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode)
+{
+       int items = 0;
+       
+       /* check if channels or only F-Curves */
+       if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {
+               bAnimListElem *ale;
+               KeyBlock *kb;
+               
+               /* loop through the channels adding ShapeKeys as appropriate */
+               for (kb= key->block.first; kb; kb= kb->next) {
+                       /* skip the first one, since that's the non-animateable basis */
+                       // XXX maybe in future this may become handy?
+                       if (kb == key->block.first) continue;
+                       
+                       /* only work with this channel and its subchannels if it is editable */
+                       if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
+                               /* only include this track if selected in a way consistent with the filtering requirements */
+                               if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) {
+                                       // TODO: consider 'active' too?
+                                       
+                                       /* owner-id here must be key so that the F-Curve can be resolved... */
+                                       ale= make_new_animlistelem(kb, ANIMTYPE_SHAPEKEY, NULL, ANIMTYPE_NONE, (ID *)key);
+                                       
+                                       if (ale) {
+                                               BLI_addtail(anim_data, ale);
+                                               items++;
+                                       }
+                               }
+                       }
+               }
+       }
+       else {
+               /* just use the action associated with the shapekey */
+               // FIXME: is owner-id and having no owner/dopesheet really fine?
+               if (key->adt && key->adt->action)
+                       items= animdata_filter_action(anim_data, NULL, key->adt->action, filter_mode, NULL, ANIMTYPE_NONE, (ID *)key);
+       }
+       
+       /* return the number of items added to the list */
+       return items;
+}
+
 #if 0
 // FIXME: switch this to use the bDopeSheet...
 static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
@@ -1944,9 +2018,11 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode
                        }
                                break;
                                
-                       case ANIMCONT_SHAPEKEY:
+                       case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
                        {
-                               //items= animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
+                               /* the check for the DopeSheet summary is included here since the summary works here too */
+                               if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
+                                       items= animdata_filter_shapekey(anim_data, data, filter_mode);
                        }
                                break;
                                
index 271827c2aba9bac6fcb43deaae005cf062fc2ad7..316f1b58d339f967e36b279f91e196907a39f16f 100644 (file)
@@ -99,7 +99,7 @@ typedef struct bAnimListElem {
        void    *data;                  /* source data this elem represents */
        int     type;                   /* one of the ANIMTYPE_* values */
        int             flag;                   /* copy of elem's flags for quick access */
-       int     index;                  /* copy of adrcode where applicable */
+       int     index;                  /* for un-named data, the index of the data in it's collection */
        
        void    *key_data;              /* motion data - mostly F-Curves, but can be other types too */
        short   datatype;               /* type of motion data to expect */
@@ -144,7 +144,7 @@ typedef enum eAnim_ChannelType {
        ANIMTYPE_DSMBALL,
        ANIMTYPE_DSARM,
        
-       ANIMTYPE_SHAPEKEY,              // XXX probably can become depreceated???
+       ANIMTYPE_SHAPEKEY,
        
        ANIMTYPE_GPDATABLOCK,
        ANIMTYPE_GPLAYER,
@@ -209,7 +209,7 @@ typedef enum eAnimFilter_Flags {
 #define FILTER_MAT_OBJC(ob) ((ob->nlaflag & OB_ADS_SHOWMATS))
 #define FILTER_PART_OBJC(ob) ((ob->nlaflag & OB_ADS_SHOWPARTS))
        /* 'Sub-object' channels (flags stored in Data block) */
-#define FILTER_SKE_OBJD(key) ((key->flag & KEYBLOCK_DS_EXPAND))
+#define FILTER_SKE_OBJD(key) ((key->flag & KEY_DS_EXPAND))
 #define FILTER_MAT_OBJD(ma) ((ma->flag & MA_DS_EXPAND))
 #define FILTER_LAM_OBJD(la) ((la->flag & LA_DS_EXPAND))
 #define FILTER_CAM_OBJD(ca) ((ca->flag & CAM_DS_EXPAND))
@@ -232,6 +232,10 @@ typedef enum eAnimFilter_Flags {
 #define EDITABLE_FCU(fcu) ((fcu->flag & FCURVE_PROTECTED)==0)
 #define SEL_FCU(fcu) (fcu->flag & (FCURVE_ACTIVE|FCURVE_SELECTED))
 
+/* ShapeKey mode only */
+#define EDITABLE_SHAPEKEY(kb) ((kb->flag & KEYBLOCK_LOCKED)==0)
+#define SEL_SHAPEKEY(kb) (kb->flag & KEYBLOCK_SEL)
+
 /* Grease Pencil only */
        /* Grease Pencil datablock settings */
 #define EXPANDED_GPD(gpd) (gpd->flag & GP_DATA_EXPAND) 
index c42e555d562e3f519b32c7924a287d4b0a022d08..e86abf124249104a883faa3011a30366a96a642d 100644 (file)
@@ -80,6 +80,7 @@ typedef struct Key {
 #define KEY_RELATIVE    1
 
 /* key->flag */
+#define KEY_DS_EXPAND  1
 
 /* keyblock->type */
 #define KEY_LINEAR      0
@@ -87,8 +88,9 @@ typedef struct Key {
 #define KEY_BSPLINE     2
 
 /* keyblock->flag */
-#define KEYBLOCK_MUTE          1
-#define KEYBLOCK_DS_EXPAND     2
+#define KEYBLOCK_MUTE                  (1<<0)
+#define KEYBLOCK_SEL                   (1<<1)
+#define KEYBLOCK_LOCKED                        (1<<2)
 
 #endif