Have questions about the new Keybinding API? Ask them there!
#Keybinding API Office Hours
1 messages Β· Page 1 of 1 (latest)
What's the recommended way to implement Ctrl+Click or Shift+Click? I was previously checking _downkeys on the click event listener:
game.keyboard._downKeys.has("Control") || game.keyboard._downKeys.has("Shift");```
Should I just change those to all caps (`CONTROL` and `SHIFT`) and that's it?
short answer is yes, but _downKeys is deprecated.
longer answer is one I talked with @flint remnant about, which is to register an Action to keep track of the state of something being held, which would allow Users to configure what key that is:
game.keybindings.register("my-module", "interaction-modifier", {
name: "Modifier key for dragging and clicking",
uneditable: [
{
key: "SHIFT"
}
],
onDown: () => { console.log("Shift Down") },
onUp: () => { console.log("Shift Up") }
})
Could I make it editable instead? Since there is no UI for keybindings yet, this will just mean that it can be edited with the set command, right?
absolutely, it was just an example
uneditable can never be unset, but can be added to. editable can be overridden. Both allow a user to bind new bindings to the action
What's the use case for uneditable in that case?
I just added keybinding support (locally) to 4 of my modules and I noticed a few things which were unexpected:
I originally sxpected a modifier field, but, when I found out that it's called modifiers and takes an array, I thought that meant that all of the keys in the array would need to be held in order to fire the keybind. Is there another way to create keybindings which require multiple modifiers to be held simultaneously?
Not sure why, but I expected to see my keybindings at the bottom of the Controls Reference and I think that could be a useful feature.
The SHIFT key doesn't fire it's onUp... (it might actually be the CONTROL key that doesn'tβI'll check in the morning)
Setting a keybinding for the arrow keys, overrides and removes your ability to move around tokens.
Shift definitely does fire onUp.
We use uneditable a bunch in core to ensure that Space always pauses, but that the User can additionally bind, say, P to Pause
if multiple modifiers isn't being required, that may be a bug, will check.
UI for keybind management is coming in Testing Phase!
All keys should fire onUp, if they don't, please log a bug
Yeah, CONTROL is definitely does not fire an onUp:
game.keybindings.register(Ctg.ID, "rollGroupInitiative", {
name: "Roll Group Initiative",
hint: "When pressed down, clicking on any of the initiative rolling buttons in the Combat Tracker will result in a Group Initiative roll.",
uneditable: [
{
key: "SHIFT"
},
{
key: "CONTROL"
}
],
onDown: () => { console.log("DOWN"); Ctg.groupInitiativeKeybind = true; },
onUp: () => { console.log("UP"); Ctg.groupInitiativeKeybind = false; },
}));```
Also, onUp is not firing if the context menu is open while the key is released
the context menu? The right click one?
Yep, with my Default Context Menu module which re-enables it. I understand why it wouldn't be up to Core to fix, but it's still a Core bug...
it's possible the context menu eats Keyboard events, in which case there is nothing we can do about it
if you run CONFIG.debug.keybindings = true in your console, you can see the system at work
Control does capture on UP, so it's likely something else is consuming the event before your Keybind Action
It says "no matching keybinds" even if there are
what is the output of your game.keybindings.activeKeys?
They are there
I grabbed your module and gave it a try, the browser is taking all Keyboard events before our system gets it while the context menu is open
So, there is nothing you can do about it?
nope π¦
Using the browser keydown/keyup event listeners worked...
I guess I could register one of those too as a fallback
Just for the keyup
that is what we're using ourselves:
window.addEventListener('keydown', (event) => this._handleKeyboardEvent(event, false));
window.addEventListener('keyup', (event) => this._handleKeyboardEvent(event, true));
hmm, we do skip isComposing events, perhaps the context menu counts as that?
nope, our handler isn't even getting hit while the context menu is open
Oh, nevermind. This happens regardless when I do it myself
browsers do a fair bit to make sure malicious JS doesn't stop default behaviors users expect
Yep, but I have found the default context menu very useful for inspecting elements quickly
although now that I think about it, perhaps we should also protect keys such as F5, which can be prevented from doing default behavior
yeah I see the appeal. I don't think it's a big deal that keybinds don't work while the context menu is open personally
Can I do anything else to help you reproduce this?
Or is this a #872553750877835264?
throw a bug in there so I can track it on Monday
FYI I was able to replicate and resolve this bug
@young dragon and @hoary furnace thanks for your feedback thus far, we will still be deprecating the private _downKeys, but in favor of a new public downKeys https://gitlab.com/foundrynet/foundryvtt/-/issues/6139
Great! i think it's a very usefull api to have
it is still encouraged to use Keybind Action workflows in cases where it makes sense to allow the User to choose their own Keys to alter behavior - we hope to offer Controller support in the future, and someone may want to modify the drag with right bumper for instance
Yeah, of course π
Thanks for listening to our feedback π
I'm still experiencing this issue: https://gitlab.com/foundrynet/foundryvtt/-/issues/6149
on v9t1 build 233
EDIT: fixed in v9t2
for my module (Alternative Rotation) the use case is:
- while a user is holding Shift, if the user drags a token, it rotates the token instead
- while a user is holding Shift and Control, if the user drags a token, it rotates the token instead
I am able to create a single key for either of them - e.g. Shift for rotating works - but I don't know whatregisterparameters I need to use to allow the option of basically an optional Control modifier on top of the Shift modifier.
I tried independently registering Shift and Control, but then if the user is already holding Shift and presses down Control, the key binding is not triggered.
I tried playing around with it but couldn't find a good way to get a trigger when Shift is up, Shift is down, Ctrl is up, Ctrl is down (regardless of whether the other one is down). I could only see a "Shift up", "Shift+Control up", "Control+Shift Down", etc. when I have both of them pressed.
You should register shift as the key, and control in reservedModifiers
You can then check the context in your action to see if control is pressed
why does this code here create a Keybind on C instead of shift+C?
game.keybindings.register("a11y-chatfinder", "chatfinder", {
name: "Chatfinder",
hint: "Puts a cursor in the chat window and activates it.",
editable: [
{
key: "C",
modifiers: "SHIFT"
}
],
onDown: async () => {
let element = $("#chat-message");
element.focus();
await new Promise(resolve => {setTimeout(resolve, 50);});
element.val("");
},
onUp: () => {},
restricted: false,
reservedModifiers: [],
precedence: CONST.KEYBINDING_PRECEDENCE.PRIORITY
});
```found it. this code works now.
also wanna say it's nice working with this. It doesn't break on the things the last lib I worked with did.
(or my own very bad code for that matter)
What was the issue?
Thanks! It was built with the previous library creators giving input so I could learn from their pain points
Instead of editable.modifiers I had SHIFT in requireredModifiers.
just to be sure ```js
isAlt(event) {
return game.keyboard.isModifierActive(KeyboardManager.MODIFIER_KEYS.ALT);
return game.keyboard.downKeys.has("ALT");
}
isCtrl(event) {
return game.keyboard.isModifierActive(KeyboardManager.MODIFIER_KEYS.CONTROL);
return game.keyboard.downKeys.has("CONTROL");
}
isShift(event) {
return game.keyboard.isModifierActive(KeyboardManager.MODIFIER_KEYS.SHIFT);
return game.keyboard.downKeys.has("SHIFT");
}```works and I can delete the second lines?
and since you wanted to help @azure ocean, this is correct syntax when I want to believe in V9 not breaking the deal any further? json "minimumCoreVersion": "9.236", "compatibleCoreVersion": "9"
correct!
bingo
okay, TAH fix is pushed π
while you are mucking in Keybinding Code: make my latest module obsolete pl0x? Nath said you should ;P
not today but it's in the features
might be stable might wait til v10
oke. Updated that one too anyway. now to mint those releases and announce them.
what's your module
shift-c for chat?
actually - since I want to have this out at release - I need another look at the modifiers on editable. Are those really an array because I tested a11y-chatfinder with just "SHIFT" and it worked
that one.
link me the repo
why do you set val to empty? Is focusing not enough?
I do not know for sure, I was following a guide. I am good at implementing what others already gave me
I don't think it's necessary. There are other ways to clear the chat (with the keyboard) after focusing on it. This could be confusing and undesirable
I'm also in favor of adding some QoL shortcuts for various mouse-based actions, though I would prefer if they were not uneditable
https://docs.google.com/document/d/1__zQgta_2gIXf7EVN2iHzFD8Z6dmBiyxpN8zwmiYEnY/edit#
I'd have to ask a player of mine if we can skip that line.
the ability to register (and presumably mix) Mouse bindings has come up often, so I feel pretty confident V2 of Action Bindings will include something for this
I'll ask since I don't have a screen reader to compare that function to other sites handling of it.
we were previously auto-converting a single value to an Array, but I think we are more strict that it has to be an Array now
sorry, I was probably unclear, though I am happy about what you said!
what I meant is just hotkeys for stuff like opening the chat or changing tabs in a window
ah! yeah, we'll likely expand what Actions are available in Core, even inside of V9 Stable (since that's a safe change)
submitting requests to our GL is the best way to get them considered
Thank you very much, adjusted it! π
Alright, here's the change I want to see before I make this core, shared mostly for insight into why we don't just copy-paste modules in:
- Use native HTML Dom rather than JQuery
const chatInput = document.getElementById("chat-message");
chatInput.focus();
- If the user is not on the Chat Tab, the Tab should be swapped to first rather than the Keybinding failing to do what it says it should
Is it still possible to register a keybinding with a modifier key like Shift as only key like this: ```js
uneditable: [
{
key: KeyboardManager.MODIFIER_KEYS.SHIFT
},
]
It's great to see that jQuery is being replaced with Vanilla JS!
I noticed that the code for the Support window uses some jQuery which could easily be cleaned out too
It's a slow process, we are trying to remove more than we add haha
Yes, but you need to use ControlLeft and ControlRightsince they are separate buttons
@azure ocean I saw the notification about a breaking change in the keybinding on my phone earlier while I was out but can't see it now... do I need to change anything in this, please?
if (isNewerVersion(game.version, "9.230")){
game.keybindings.register("fate-core-official", "fcoInteractionModifier", {
name: "Fate Core Official modifier key for dragging and clicking",
uneditable: [
{
key: "SHIFT"
}
],
onDown: () => { game.system["fco-shifted"] = true; },
onUp: () => { game.system["fco-shifted"] = false; }
})
}```
Your key now needs to be βShiftLeftβ or βShiftRightβ or both
yep, you'd want to update your isNewerVersion to check 9.236 and use both ShiftLeft and ShiftRight
Okay, is that key:["ShiftLeft", ShiftRight"]
Or, do I need to register it as two rules?
uneditable: [
{
key: "ShiftLeft"
},
{
key: "ShiftRight"
}
],
This should work then, thanks:
if (isNewerVersion(game.version, "9.230")){
if (!isNewerVersion(game.version, "9.235")){
game.keybindings.register("fate-core-official", "fcoInteractionModifier", {
name: "Fate Core Official modifier key for dragging and clicking",
uneditable: [
{
key: "SHIFT"
}
],
onDown: () => { game.system["fco-shifted"] = true; },
onUp: () => { game.system["fco-shifted"] = false; }
})
}
if (isNewerVersion(game.version, "9.236")){
game.keybindings.register("fate-core-official", "fcoInteractionModifier", {
name: "Fate Core Official modifier key for dragging and clicking",
uneditable: [
{
key: "ShiftLeft"
},
{
key: "ShiftRight"
}
],
onDown: () => { game.system["fco-shifted"] = true; },
onUp: () => { game.system["fco-shifted"] = false; }
})
}
}```
Well, after I fix the conditional... I'll reverse those and make the 9.235 an else.
i need to toggle a variable on ALT press, how should i do it now? it seems to no longer be working
const {SHIFT, CONTROL, ALT} = KeyboardManager.MODIFIER_KEYS;
game.keybindings.register(SMARTTARGET_MODULE_NAME, "altKey", {
name: game.i18n.localize("smarttarget.keybindings.altkey"),
editable: [
{key: ALT}
],
onDown: () => {game.smartTarget.altModifier = true;},
onUp: () => {game.smartTarget.altModifier = false;},
});
just like with Skimble's Shift, you'll now need AltLeft and AltRight
Exact same answer as immediately prior question
Control, Alt, and Shift are both modifiers and buttons
In the context of a key, they exist as both Left and Right
In the context of a Modifier, we join them together, so use KeyboardManager.MODIFIER_KEYS
ah whops, my bad
alternative approach with slightly less copy-paste
if (isNewerVersion(game.version, "9.230")) {
let uneditable = [
{
key: "SHIFT"
}
];
if (isNewerVersion(game.version, "9.236")) uneditable = [
{
key: "ShiftLeft"
},
{
key: "ShiftRight"
}
];
game.keybindings.register("fate-core-official", "fcoInteractionModifier", {
name: "Fate Core Official modifier key for dragging and clicking",
uneditable: uneditable,
onDown: () => { game.system["fco-shifted"] = true; },
onUp: () => { game.system["fco-shifted"] = false; }
})
}
I might switch these to editable now there's a UI for that; is that just as simple as switching to editable [...
yep!
Oh yeah, that's a neat idea.
sorry for not reading above but i'm kind of speedrunning the 4 broken mods from this change since i don't have holidays but instead crunch at work π
are custom keybinds world settings?
they exist in game.keybindings not game.settings
but they are stored per-user if that's what you meant
per client
you can have different keybindings for your laptop or your pc or your hampsterwheel with custom axis inputs hooked into Foundry
our hampsterwheel users are our most important ones
Hmm, is the keybinding ui supposed to look like this or is something going wrong?
ctrl+f5
I thought the caching was fixed. π
but should I have no option to add a keybind to a not-bound action?
Aha, thanks for that.
You should, but apparently I missed that. Bug already logged here: https://gitlab.com/foundrynet/foundryvtt/-/issues/6314
For now, use key: "F24" since that's not a real key
Okay, hmm. So I changed it to 'editable' and I've tested changing the key binding for my Fate Core Official example, but the new key isn't working.
It seems to be checking for it, but it's not toggling my boolean.
It's still responding to SHIFT even though it has been edited to be ctrl.
could you get a set of reproduction steps?
Actually, belay that, I think I have some other conditional checks in my code that's still using the legacy behaviour in certain places.
Lol, I picked the one modifier key use to test it where I used this as the code:
let umr = false;
if (event.shiftKey && !game.settings.get("fate-core-official","modifiedRollDefault")) umr = true;
if (!event.shiftKey && game.settings.get("fate-core-official","modifiedRollDefault")) umr = true;
if (umr){
await target.rollModifiedSkill(event.target.id);
}
else {
await target.rollSkill(event.target.id);
}```
Hahaha
So it's good?
Just checking. When I used leftCtrl to replace the keybinding it doesn't fire the keyUp event, but I suspect that's a known thing?
It works when I replace it with v (as a random test) though
Hmm. this might be a bug. When I deleted the new keybinding, it returned to SHIFT and that broke it. I had to manually put back in ShiftLeft and ShiftRight.
Ahh, I think that's because I should've been checking for isNewerVersion 9.235, as 236 is not a greater version than 236
Yup, that was it!
What would be the convention for overwriting default keybindings in a system? Iβm using alt as a modifier key in the Cypher System for alternative functions of buttons because thatβs the one key that all OSs and browsers have in a similar way. I was using ctrl for a while, but then some browsers and OSs register ctrl-click as a right-click. But since alt also highlights all tokens, that can mean a performance hit when a lot of tokens are on the canvas. So I wrote Free Alt as a module, which re-maps highlighting tokens to H. I was thinking of re-mapping this for the Cypher System using the new API, but would that be considered bad practice, as it might be confusing across different systems? Would it be expected that systems re-bind default functions to make the system-specific experience better?
This probably would not be advisable. Keybindings are a client-side setting, so your set of mapped keybindings is used for all the worlds you play. This means that the default keybindings in your dnd5e world and the default keybindings in your cypher world should probably be the same, aside from any system-specific bindings that exist or modifications that you (the client) have made yourself.
Now that "Highlight Objects" is re-bindable, users can choose if they want to avoid having ALT highlight things while used as a modifier
I have not really experienced ALT causing a notable performance issue though, even on scenes with very many tokens
Thanks! Didnβt realize that the settings were used across worlds. Makes sense.
To be fair, that was based on my old laptop on Foundry 0.7.x with about 70 tokens. I havenβt had problems since the new machine, but that roughly coincided with Foundry 0.8, so that might have helped as well.
Ok, I'm taking a look at Default Context Menu now for the breaking change:
This is what I had before:
uneditable: [
{ key: "CONTROL" }
],
Would I use KeyboardManager.MODIFIER_KEYS now?
uneditable: [
{ key: KeyboardManager.MODIFIER_KEYS.CONTROL }
],
Hmm. It doesn't seem to work
You need e.g. key: "ControlLeft" now (and ControlRight)
I have to register two separate keybindings?
Is there an enum with those?
Don't think so, and yeah, something like this is now necessary AFAIK: ```js
uneditable: [
{ key: "ControlLeft" },
{ key: "ControlRight" },
],
Yeah, that works π
it would be nice if there were an enum, but as far as I'm aware there is not. The main reason we have moved towards using canonical KeyboardEvent#code values is that these values are not maintained by us (nor are they foundrytvtt-specific). There is a documented list available here, but I don't think there is an enum for it: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
did I miss a deprecation warning on game.keyboard.isCtrl() in 08x? based on my testing... i did not
thanks to @ashen bramble for the snippet above I was able to unblock myself π
I didn't miss that either and was mad about it π
i just don't understand why those snippets you wrote weren't included as shims in the KeyboardManager class... 
don't ask me, I am just the mad dog π
i blame Cody
jk, I β€οΈ cody. shit happens.
My uneditable keybind is showing up twice
I can't add a new keybind and it tells me that there is a max of 4
Reset to default doesn't remove the duplicate for some reason
How does the precedence thing that Atropos is currently talking about on stream work?
that's weird, I'll cycle back and debug this on Monday
when registering a keybind, you can indicate that the keybind should evaluate as one of the first (PRIORITY), one of the last (DEFERRED), or in the middle (NORMAL) by setting precedence when you register, like so:
game.keybindings.register("core", "measuredRulerMovement", {
name: "KEYBINDINGS.MoveAlongMeasuredRuler",
editable: [
{key: "Space"}
],
onDown: ClientKeybindings._onMeasuredRulerMovement,
precedence: CONST.KEYBINDING_PRECEDENCE.PRIORITY,
reservedModifiers: [CONTROL]
});
What's the default if you don't include this?
NORMAL
Atro said it tries to do stuff until an event has reported that the key press is handled.
how to?
a keypress action can return true to indicate it consumes the event. If it returns false, or nothing, execution will continue
thank.
updates will flow in tomorrow, today the bot needs to find a tasty energy outlet π
@azure ocean just pinging here instead: looks like game.keyboard.isCtrl was made static at some point in the v9 cycle?
v8:
verified, will fix next build
Finally getting in to applying the new key binds. Is there any path to making key binds which work in input fields or TinyMCE? I can always match it myself, but that kind of defeats the purpose.
We specifically skip evaluating key events while inputs are focused, since it would be awful confusing for certain keys to be eaten rather than typed. What's your usecase?
I attach to input fields π
To do what?
Insert stuff, w/ Quick Insert π
Ahhh
Not a big deal to hack around it, but it's relatively error prone if you change things later.
I do not, in fact, have an encyclopedic knowledge of all authors and their modules haha
No worries, it's not a very common use case
My advice would be to use the core keybinding API to define your action and allow users to register their key of choice via the core interface, but to attach your own event listener to handle keypress events which respond to the key code that the user has bound. This approach would work for both input fields which we skip over and in TinyMCE environments.
There's a way to manually invoke the action engine, I will share when I'm actually at my desk instead of on my phone
My current hack: on document keydown, when game.keyboard?.hasFocus (or in TinyMCE), I have some handling with getKeyboardEventContext, _getMatchingActions and _executeKeybind, which will only fire if the action is one of my own.
you probably could skip some steps here rather than needing to check for matching actions, since you already know you just want your own action(s)
but that general approach seems like the right direction
upon review this is probably your best way to do it
Seems to work fine, thanks for the support!
A few notes;
Setting the hint field on the keybind registration seems to work, but it doesn't localize the string.
The categories in the keybindings window get the same class name as the module/system namespace, which is the main class I've used for my main window. Easy to fix for me, but seems a little conflict prone.
noted on the hint, that was a small miss. The Categories are probably fine, but it wouldn't hurt for us to dedupe them
Wait, uh... actionData.hint = game.i18n.localize(action.hint);

oh, I see.
Let me check again
Question, if I want to have Ctrl and Alt hotkeys to work at the same time, is there any magic I need to do?
It would also seem that game.keyboard.downKeys is updated after the onDown event and before the onUp - I guess this was intended?
You can register a keybinding with both keys:
uneditable: [
{ key: "ControlLeft" },
{ key: "ControlRight" },
{ key: "AltLeft" },
{ key: "AltRight" },
],β
Ah, so I'd have to create a keybinding for all possible combinations, even though I'd like them to work independently?
Ie, I don't care if Shift + Ctrl is pressed, only if Ctrl was pressed, and if Shift was pressed, for separate uses
So if Shift was held down at the point where I press Ctrl, I would expect CtrlDown to fire
you should put that in reservedModifiers
see the doc here: https://foundryvtt.com/api/global.html#KeybindingActionConfig
Oh, neat, thanks!
Okay, last question (I hope), if I wanted to have a distinct keybind for just Shift, and another for Ctrl + Shift (in that order), would that be possible?
as in two bindings on the same Action?
how do I control the name here?
Thinking of splitting into 3 different parts for one module
because I'll make that number go from 58 to 70+ in a moment
Kind of - I've gotten around it by just registering Shift and Control to two separate hotkeys and checking if Shift is down, or is Shift + Control is down
the name is driven by the namespace registered, which you can set to anything
you can set ShiftLeft and ShiftRight as your keys, then Control as your reservedModifier, then check the context passed in
okay, Namespace: pf2e-u-is-for-utility, but it shows up as "General"
oh well lookie there, we did make sure it was a module π
for now, you're tied to your module name, but I can expand that
that it translated into my module name is why I ask π
please do, I need it to stay sane.
that scroll isn't reasonable, but it's also all one liners that seemed reasonably handy depending on just what spells and skills the party is bringing to the table.
(can you ping me when this changes, I like being a step ahead when I can, it feels infinitely better than being one step behind)
(also once again - Mad thank you from the little community I do stuff for π β€οΈ )
there's also a search!
that does help, and I constantly find myself scrolling in windows that have a search π
Why is it called Reserved Modifiers btw? Maybe I don't understand what it does properly, but that name doesn't make much sense to me...
naming thing is hard is my short answer
we considered Optional Modifiers but that was not super clear either
they are reserved because you can't set them as the Key (which no longer even applies, but did at the time), but they aren't required
Ok. I appreciate describing them as optional (maybe that word could be used in the docs). I feel like "reserved" and "optional" are almost antonyms, but I guess it makes sense in that context.
if it wouldn't be a breaking API change, I would rename them, but we're stuck with them now
For sure π
does this not capture that they are optional when you read it? Modifiers such as [ "CONTROL" ] that can be also pressed when executing this Action. Prevents using one of these modifiers as a Binding.
Not really
π
writing your own docs is often hard haha. We have a #711726189693239306 for a reason
I found a bug closely related to the keyboard refactor. You can get stuck with a currentMouseManager in the DRAG state, I think it's because the keyup event is ignored when in an input field.
- Hold Ctrl
- Click an input field (or focus an input field as the result of an action)
- Release Ctrl
- Click the canvas
EDIT: Well, one of my users found it.
Probably the same bug as this #872553750877835264 message
Shared here again, so it doesn't get lost so easily: when you hold a default Firefox key-combination (like CTRL-F) for some longer time (less than 1 second) then it will still be executed by Firefox even when being "prevented".
Doesn't seem to be the case in Chrome.
I ran into a problem with return true vs. event.preventDefault(): When two modules use the same keybinding and both use return true then only one can use the binding, but if one uses event.preventDefault then both can use the same binding. Is this expected?
I only want to prevent browser default in my module, not prevent other modules from using the same keys.
We tend to feel that one keypress should do one thing, not multiple things. If you handle the keypress we assume that other potential handlers should not. You may have a use case where it makes sense for it to pass through even if you handle it, but this isnβt the assumption of our current design
Ok, so it is expected behavior. Thanks for the clarification.
I've tried reading over the docs, but I'm still a little confused regarding reserved modifiers.
Could I get an example of when it would be better to do one over the other?
game.keybindings.register("myModule", `myKeybinding`, {
name: "",
hint: "",
editable: [{
key: `KeyA`,
modifiers: ["Control"]
}],
onDown: () => console.log("Control + A was pressed"),
restricted: false
});
game.keybindings.register("myModule", `myKeybinding`, {
name: "",
hint: "",
editable: [{
key: `KeyA`
}],
onDown: () => console.log("Control + A was pressed"),
restricted: false,
reservedModifiers: ["Control"]
});
In the first option, the keybinding will only be activated if CTRL+A is pressed, i.e. CTRL is required in order to activate the handler
in the second option CTRL has some ancillary behavior as part of the keybind handler, so the binding will activate if you press A OR it will also activate if you press CTRL+A, but the behavior of the handler may differ depending on whether or not CTRL is pressed
an example of the first configuration would be CTRL+C to copy tokens, you must use CTRL+C to copy
an example of the second configuration (there isn't an example in the core software, so this one is made up) would be if T would target a token but CTRL+T would target that token AND pan the canvas to center on your target (as a made up example)
great explanation, thanks!
How does a module implement the second configuration?
I don't understand the question, the code enso posted above is valid
I mean, how does the module handle A vs. CTRL+A in the second case when there is only one onDown?
inside the handler function you decide what functionality to implement depending on whether CTRL is also pressed or not
So the module query the keyevent for CTRL? Is that advantageous versus registering two keybinding (one for A and one for CTRL+A)?
the handler is provided with the KeyboardEventContext object, so you can easily check context.isControl inside the handler to know if the modifier is applied or not
We would recommend registering two events when the behaviors are substantially different to the point that the user would want to bind them as different keystrokes completely.
We would recommend using one event with an optional modifier in cases where the modifier provides a slight alteration to the behavior
So the shift modifier for turning +-5 ft to +-10 ft in my module might better be implemented via reservedModifier. I will think about that. Thanks for the explanation.
yes, if you set shift as a reserved modifier, you can then check context.isShift inside the handler
and toggle whether to do 5ft vs 10ft
I will think about it. Currently I am using 5 keybindings, 2 for +-5, 2 for +-10, might be better, might be worse.
I think the answer is probably "no" but is there any way to get keybinds to be recognized while the chat message text area is focused?
Wrap KeyboardManager.prototype.hasFocus
I think it would be preferable in this case for you to register your own keydown event on the chat message input and parse the keyboard event against registered keybindings using:
const context = KeyboardManager.getKeyboardEventContext(event);
const actions = KeyboardManager._getMatchingActions(context);
this is a bit outside of our intended flow. Normally keybindings wouldn't apply within the context of text input
