Reputation: 79
I'm writing a VueJS application that will have a custom context menu that appears when the user mouses over a particular item on the page. The menu is dynamic meaning that it will change as the user hovers over different items. If the user holds down the control key the menu will be static so that they can interact with the items in the menu.
My issue is the while the @keydown.ctrl="..."
event seems to respond as intended the @keyup.ctrl="..."
event does not. I have looked around and tried different modifiers such as .exact
and .caputure
but they don't seem to solve the issue.
What does work however is changing @keyup.ctrl
to @keyup.control
. The .control
works on the @keyup
event but not for the @keydown
event.
What is the difference between @keydown
and @keyup
that would require the use of different key modifiers?
Below is an example of what the root element looks like.
<div
tabindex="0"
@keydown.esc.exact="() => (displayContext = false)"
@keydown.ctrl.exact="() => (keepContext = true)"
@keyup.control="() => (keepContext = false)"
>
...
</div>
Upvotes: 2
Views: 1942
Reputation: 46594
You can use this website to visually which keys are triggering which event: https://config.qmk.fm/#/test
or even on this one: http://keycode.info/
As you can see, you cannot have a listener on the ctrl key alone. You either need a ctrl + a
or another key paired with it to effectively track it.
Here is the best implementation that we can have to track the ctrl
event without any other key pressed:
ctrl
and hover the div (@mouseover.ctrl="holdCtrlAndHover"
)ctrl
, leave the div (@mouseleave.ctrl="holdCtrlAndLeave"
)ctrl
, hover on the div, then mouse click (@click.ctrl="hoverAndHoldCtrlThenMouseClick"
)Example of the implementation: https://codesandbox.io/s/lingering-violet-q5gct?file=/src/App.vue
For a quick reference on MouseEvent.ctrlKey
, here it is: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/ctrlKey
Here is a quick explanation of the differences on the event key listeners: onKeyPress Vs. onKeyUp and onKeyDown
Good to know: keypress
event is now deprecated
Upvotes: 2
Reputation: 1075
There may be a couple of problems related to this.
Capturing keydown events (from vue template) is most reliable when you are trying to capture keydowns of an input (input, select or textarea) element. Because when you focus on the element all keyboard events are triggered on the this element. In your example you have a few divs on the page and these may not be the active element. A suitable workaround for this would be to capture all keydown or key keyup events on the document.body and checking if the event.target matches your criteria. Another benefit is you can keep your template code simpler (especially when you have many contextmenu areas.)
mounted() {
this.keepContext = false;
document.body.addEventListener('keydown', event => {
if (event.key == 'Control') {
this.keepContext = true;
}
});
document.body.addEventListener('keyup', event => {
if (event.key == 'Control') {
this.keepContext = false;
} else if (event.key == 'Escape') {
// hide the contextmenu
}
});
}
Another subject that you raised, the difference between @keydown.ctrl and @keydown.control.
The first: the .ctrl event modifier is usually used in combination with another key, (example: '@keydown.ctrl.s="autoSave"')
The second: .control is fired when you press the key control
and cannot be used in combination with another key.
I have experimented with these two setups:
<input
@keydown.control="logKeydown"
@keyup.control="logKeyup">
>
and this
<input
@keydown.ctrl="logKeydown"
@keyup.ctrl="logKeyup">
>
And the setup with @keydown.control does works reliably. The @keyup.ctrl does not work reliably (sometimes it misses the keydown, sometimes it misses the keyup).
All in all I'd recommend listening to keyboard events on the document.body when using non-input elements. Second best is using the .control modifier (instead of the .ctrl) modifier.
Upvotes: 1