Summary
I am trying to configure React Grab so either Cmd+C or Ctrl+C can trigger the copy/grab shortcut on macOS.
Using a function activationKey lets the keydown path recognize both shortcuts, but Ctrl+C still does not reliably activate/copy. It looks like the keyup/release path derives required modifiers from the platform default when activationKey is a function, so on macOS it still treats Meta as the required modifier even when the custom matcher matched Ctrl+C.
Example configuration
import { getGlobalApi } from "react-grab";
const reactGrab = getGlobalApi();
reactGrab?.setOptions({
activationKey: (event) => {
const key = event.key.toLowerCase();
const isCopyKey = key === "c" || event.code === "KeyC";
return isCopyKey && (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey;
},
keyHoldDuration: 0,
});
Expected behavior
When activationKey is a function and returns true for Ctrl+C, React Grab should use that matched shortcut consistently for the full hold/copy lifecycle.
In this case, both Cmd+C and Ctrl+C should be viable on macOS.
Actual behavior
Cmd+C behaves as expected on macOS, but Ctrl+C does not reliably trigger/copy, even when activationKey returns true and keyHoldDuration is set to 0.
Source-level notes
From reading the current source:
packages/react-grab/src/utils/is-target-key-combination.ts honors a function activationKey in the keydown path.
packages/react-grab/src/utils/parse-activation-key.ts has getModifiersFromActivationKey(), but for a function activation key it returns platform defaults:
- macOS:
metaKey: true
- non-macOS:
ctrlKey: true
packages/react-grab/src/core/index.tsx uses getRequiredModifiers() in the keyup path to compute isReleasingModifier.
That means a function matcher can say "this Ctrl+C keydown is valid", but the later release logic still appears to evaluate macOS Meta as the required modifier. For an OR-style shortcut like Cmd+C or Ctrl+C, there does not seem to be a way for the function matcher to also tell React Grab which modifier/key combination was actually matched.
There is also a MIN_HOLD_FOR_ACTIVATION_AFTER_COPY_MS gate in the keyup path, so setting keyHoldDuration: 0 is not enough to make a normal Ctrl+C press work reliably.
Why this matters
The string form can represent one shortcut such as "ctrl+c", but it cannot represent an OR shortcut like "use Cmd+C or Ctrl+C". The function form is the natural API for that, but today it loses release/modifier semantics.
Possible fixes
A few possible directions:
- Let
activationKey accept an array of strings/functions, e.g. ["cmd+c", "ctrl+c"], so modifier metadata remains parseable.
- Add an optional way for function matchers to declare required modifiers.
- Track the shortcut/modifiers that actually matched on keydown and use that for keyup/release handling instead of falling back to platform defaults for function activation keys.
Related but not the same as #398, which is about copy behavior while the toolbar is minimized. This issue is specifically about function activationKey release semantics on macOS.
Summary
I am trying to configure React Grab so either
Cmd+CorCtrl+Ccan trigger the copy/grab shortcut on macOS.Using a function
activationKeylets the keydown path recognize both shortcuts, butCtrl+Cstill does not reliably activate/copy. It looks like the keyup/release path derives required modifiers from the platform default whenactivationKeyis a function, so on macOS it still treatsMetaas the required modifier even when the custom matcher matchedCtrl+C.Example configuration
Expected behavior
When
activationKeyis a function and returnstrueforCtrl+C, React Grab should use that matched shortcut consistently for the full hold/copy lifecycle.In this case, both
Cmd+CandCtrl+Cshould be viable on macOS.Actual behavior
Cmd+Cbehaves as expected on macOS, butCtrl+Cdoes not reliably trigger/copy, even whenactivationKeyreturnstrueandkeyHoldDurationis set to0.Source-level notes
From reading the current source:
packages/react-grab/src/utils/is-target-key-combination.tshonors a functionactivationKeyin the keydown path.packages/react-grab/src/utils/parse-activation-key.tshasgetModifiersFromActivationKey(), but for a function activation key it returns platform defaults:metaKey: truectrlKey: truepackages/react-grab/src/core/index.tsxusesgetRequiredModifiers()in the keyup path to computeisReleasingModifier.That means a function matcher can say "this Ctrl+C keydown is valid", but the later release logic still appears to evaluate macOS
Metaas the required modifier. For an OR-style shortcut likeCmd+CorCtrl+C, there does not seem to be a way for the function matcher to also tell React Grab which modifier/key combination was actually matched.There is also a
MIN_HOLD_FOR_ACTIVATION_AFTER_COPY_MSgate in the keyup path, so settingkeyHoldDuration: 0is not enough to make a normal Ctrl+C press work reliably.Why this matters
The string form can represent one shortcut such as
"ctrl+c", but it cannot represent an OR shortcut like "useCmd+CorCtrl+C". The function form is the natural API for that, but today it loses release/modifier semantics.Possible fixes
A few possible directions:
activationKeyaccept an array of strings/functions, e.g.["cmd+c", "ctrl+c"], so modifier metadata remains parseable.Related but not the same as #398, which is about copy behavior while the toolbar is minimized. This issue is specifically about function
activationKeyrelease semantics on macOS.