3

I know that the keyboard menu key is keyCode === 93.

So I have the following code:

$(window).on("keydown", document, function(event){
    if (event.keyCode === 93)  {   //context menu
        console.log("context menu key", event);
        event.preventDefault();
        event.stopPropagation();
        return false;
    }
});

Although the event does fire, and the console does get logged inside the if statement, but the context menu still shows even though both event.preventDefault(); and event.stopPropagation(); are present in my code.

Is there any way to prevent the menu from being displayed?

Demo for fiddling: http://jsfiddle.net/maniator/XJtpc/


For those of you who do not know what the "menu" key is:

Community
  • 1
  • 1
Naftali
  • 144,921
  • 39
  • 244
  • 303
  • You want to allow the right click context menu to work though? If you don't you should use bind to the contextmenu event instead of keydown. – aquinas Aug 20 '12 at 17:08
  • Modern day browsers have settings that may prevent you from blocking context menus. – epascarello Aug 20 '12 at 17:08
  • @aquinas I want the right click menu to work. I do **not** want to block that... – Naftali Aug 20 '12 at 17:08
  • Can you log the event.keyCode to confirm your keyboard is indeed sending keyCode 93? – Bot Aug 20 '12 at 17:13
  • @Bot you obviously did **not** read the OP.... – Naftali Aug 20 '12 at 17:14
  • 1
    @Neal your question is not clear, you say the event fires which to me means your keypress fired but doesn't mean your if statement fired. – Bot Aug 20 '12 at 17:15
  • @Bot I said everything works. the console.log and all. Did you even look at my demo at all?? – Naftali Aug 20 '12 at 17:17
  • @Neal your question does not say "everything works" and your issue is keyboard specific. Not everyone has a keyboard with a contextmenu key. – Bot Aug 20 '12 at 17:19
  • @Neal ---nothing in your question states this, you merely say the event does fire. So Bot is not incorrect in questioning this--- *Ninja'd* – rlemon Aug 20 '12 at 17:19
  • @rlemon I edited my question to better mirror what happens. – Naftali Aug 20 '12 at 17:20

3 Answers3

3

This is kind of dumb but it seems to work: http://jsfiddle.net/XJtpc/2/ :)

$(function(){
    var lastKey=0;
    $(window).on("keydown", document, function(event){
        lastKey = event.keyCode;            
    });

    $(window).on("contextmenu", document, function(event){
        if (lastKey === 93){
            lastKey=0;
            event.preventDefault();
            event.stopPropagation();
            return false;
        }
    });
});
​
aquinas
  • 23,318
  • 5
  • 58
  • 81
  • Wow.... ingenious :-)..... Hmmm now I have to try to fig out how to **not** sully the global scope.... – Naftali Aug 20 '12 at 17:17
  • 1
    It's not in the global scope, see how I wrapped it in a jquery ready function? – aquinas Aug 20 '12 at 17:17
  • Yea, but those events do not really need to be in a ready function since they are delegated.... – Naftali Aug 20 '12 at 17:18
  • Well, true, I just tend to wrap things that way when using jQuery, but yes, can just do the (function(){})() trick. Whatever you prefer. – aquinas Aug 20 '12 at 17:25
  • Just from testing (although it is hard because I don't have a menu key) would this not block the next contextmenu (right click) if they have opened it, and not pressed any keys in the interm? Some browsers may not fire the oncontextmenu event when opening it from the keyboard? or do they? Again this is hard to test on my end. – rlemon Aug 20 '12 at 17:26
  • @rlemon `contextmenu` is a blocking event. until it is cleared, you cannot do it again. In this case, once the event is over, the contextmenu event is cleared, and you can right click again. – Naftali Aug 20 '12 at 17:28
0

I started with @aquinas' solution but discovered it can be a bit simpler than that.

Steps

  1. Register keydown event handler. e.preventDefault not required.
  2. Register contextmenu event handler and just do e.preventDefault()

Example:

// JavaScript
// Register your `ContextMenu` key event handler
document.querySelector('body').onkeydown = (e) => {
  if (e.key === 'ContextMenu') {
    // Do something
  }
}

// Prevent `contextmenu` event default action
document.querySelector('body').oncontextmenu = (e) => e.preventDefault();


// jQuery
// Register your `ContextMenu` key event handler
$('body').on('keydown', (e) => {
  if (e.key === 'ContextMenu') {
    // Do something
  }
});

// Prevent `contextmenu` event default action
$('body').on('contextmenu', (e) => e.preventDefault());

pseudosavant
  • 7,056
  • 2
  • 36
  • 41
0

The trick is that it's the keyup event, not the keydown event that triggers the context menu. Calling .preventDefault() on a keyup event whose .key is ContextMenu will stop it from happening, at least in Chrome and Electron.

That is, you can globally disable the context menu key just with:

window.addEventListener("keyup", function(event){
    if (event.key === "ContextMenu") event.preventDefault();
}, {capture: true})

And then monitor the keydown event to trigger your replacement.

PJ Eby
  • 8,760
  • 5
  • 23
  • 19