Could you provide a formula for determining keyboard shortcuts values?

Hi @Andreas_Hegenberg - I was curious if you could provide what calculations lay behind the values of
"BTTAdditionalConfiguration" and "BTTShortcutModifierKeys" for keyboard (shortcut) related actions.

I mean, I could find some patterns that particular modifiers have specific values, and combining modifiers just sums those variables values. But there were some inconsitencies in some cases + I just wanted to know particular purpose of both BTTAdditionalConfiguration and BTTShortcutModifierKeys fields.

You see, because CMD+C has "BTTAdditionalConfiguration" : "1048584" and "BTTShortcutModifierKeys" : 1048576 - so it's 1048576 vs 1048584.

ALT+C -> 524320 vs 524288
CTRL+C -> 262145 vs 262144
fn + C -> 8388608 === 8388608
CMD+ALT+C -> 1572904 (I guess 1048584 + 524320 from Additional config of particular modifiers) vs 1572864 (from shortcutModifierKeys 1048576 + 524288)

I cannot really tell where, but there were some cases where those calculations failed by 1 :confused: I suppose however, that those were the most hard to do ones , such as fn + alt + ctrl + cmd + shift + modifier. Also I don't really know how it'll behave when in differentiate mode...

My question is - could you provide some additional instructions on how to really manage those easly, and what parts of config are mandatory? (except for BTTEnabled, BTTPredefinedActionType ofc)

Because now, generating those JSONs in the fly seems really harsh :frowning: The best scenario would be that perhaps you could provide some additional field in json to make those easier (i mean keyboard related actions), but could you at least give me some tips how should I address that? ?

Hey,

it's complicated.

The basic modifiers can be generated using a function like this (quick & dirty untested):


function createBitmaskForShortcut(shortcut, differentiateLeftRight) {
  // modern flags (don't support left / right)
  const NSEventModifierFlagCapsLock = 1 << 16; // Set if Caps Lock key is pressed.
  const NSEventModifierFlagShift = 1 << 17; // Set if Shift key is pressed.
  const NSEventModifierFlagControl = 1 << 18; // Set if Control key is pressed.
  const NSEventModifierFlagOption = 1 << 19; // Set if Option or Alternate key is pressed.
  const NSEventModifierFlagCommand = 1 << 20; // Set if Command key is pressed.
  const NSEventModifierFlagNumericPad = 1 << 21; // Set if any key in the numeric keypad is pressed.
  const NSEventModifierFlagHelp = 1 << 22; // Set if the Help key is pressed.
  const NSEventModifierFlagFunction = 1 << 23; // Set if any function key is pressed.

  // nexstep flags (support left / right modifiers)
  const NX_DEVICELCTLKEYMASK = 0x00000001; // left ctrl
  const NX_DEVICELSHIFTKEYMASK = 0x00000002; //left shift
  const NX_DEVICERSHIFTKEYMASK = 0x00000004; // right shift
  const NX_DEVICELCMDKEYMASK = 0x00000008; // left cmd
  const NX_DEVICERCMDKEYMASK = 0x00000010; //right cmd
  const NX_DEVICELALTKEYMASK = 0x00000020; //left option
  const NX_DEVICERALTKEYMASK = 0x00000040; // right option
  const NX_DEVICE_ALPHASHIFT_STATELESS_MASK = 0x00000080;
  const NX_DEVICERCTLKEYMASK = 0x00002000; // right ctrl

  let bitmask = 0;
  if(differentiateLeftRight) {
    if(shortcut.indexOf('leftcmd') != -1 ) {
      bitmask |= NX_DEVICELCMDKEYMASK;
    }
    if(shortcut.indexOf('rightcmd') != -1 ) {
      bitmask |= NX_DEVICERCMDKEYMASK;

    }
    if(shortcut.indexOf('leftopt') != -1 ) {
      bitmask |= NX_DEVICELALTKEYMASK;

    }
    if(shortcut.indexOf('rightopt') != -1 ) {
      bitmask |= NX_DEVICERALTKEYMASK;

    }
    if(shortcut.indexOf('leftctrl') != -1 ) {
      bitmask |= NX_DEVICELCTLKEYMASK;

    }
    if(shortcut.indexOf('rightctrl') != -1 ) {
      bitmask |= NX_DEVICERCTLKEYMASK;

    }
    if(shortcut.indexOf('leftshift') != -1 ) {
      bitmask |= NX_DEVICELSHIFTKEYMASK;

    }
    if(shortcut.indexOf('rightshift') != -1 ) {
      bitmask |= NX_DEVICERSHIFTKEYMASK;

    }
  } else {
    if(shortcut.indexOf('cmd') != -1 ) {
      bitmask |= NSEventModifierFlagCommand;
    }
    if(shortcut.indexOf('ctrl') != -1 ) {
      bitmask |= NSEventModifierFlagControl;
    }
    if(shortcut.indexOf('opt') != -1 ) {
      bitmask |= NSEventModifierFlagOption;
    }
    if(shortcut.indexOf('shift') != -1 ) {
      bitmask |= NSEventModifierFlagShift;
    }
    if(shortcut.indexOf('function') != -1 ) {
      bitmask |= NSEventModifierFlagFunction;
    }
  }

  return bitmask;

}

Example usage:

createBitmaskForShortcut('optcmd');

The BTTAdditionalConfiguration is only used when left right differentiation is necessary and contains modifiers in an older Apple format.

Example usage:

createBitmaskForShortcut('leftopt', true);

The problem is that there is also more logic necessary to create the modifiers correctly for all types of keys and all edge cases. (e.g. arrow keys always need the function flag added ).

1 Like

Thank you very much! I'll try to play around with it :slight_smile: If I experience any problems I'll fallback to you as a guide if you don't mind, however I hope that'll be able to figure it out myself.

I've improved a formula a little bit, perhaps such cases as you described (as arrow keys, ETC) are not covered yet, however It does seem to work with all cases I've tested for both differentiate mode and not:

I'm adding the value of the locationMask to the value that'd be valid if no differentiate mode is present. It seems to be working, if I got something wrong - you can let me know. However it seems to work for my cases and I'll add support for registering keyboard actions in my next release of btt js :slight_smile:

function createBitmaskForShortcut(shortcut: string, differentiateLeftRight: boolean) {
  const usedKeys = shortcut.split('+');

  function modifyMask(cb: Function, bitmaskKey: keyof IKey) {
    usedKeys.forEach((k) => {
      const foundKey = KEYS.find((keyObj) => {
        return keyObj.key.toLowerCase() === k.toLowerCase();
      });
  
      if (foundKey && foundKey[bitmaskKey]) {
        cb(foundKey[bitmaskKey]);
      }
    });
  }

  let bitmask = 0;

  modifyMask((foundValue: number) => {
    bitmask |= foundValue;
  }, 'modifierValue');

  if (differentiateLeftRight) {
    modifyMask((foundValue: number) => {
      bitmask += foundValue;
    }, 'locationMask');
  }

  return bitmask;
}

Thanks again Andreas!