case
ADM Blog
3Apr/090

Right click and custom context menu in Flash/Flex


Anyone know you can customize your flash context menu with ContextMenu class. But what if you want to really get rid of that and use your on context menu or just use the functionality of the right button of the mouse ?

The idea is fairly simple:

1 - Use Javascript in the HTML container page to disable the right-click on top of the SWF.
2 - Capture the event and pass it to a function that communicates with Flash via the External Interface
3 - In Actionscript the function called from Javascript does whatever you need to display your own custom context-menu.

Why would anyone want to do this?

Well, there are several very important reasons:

1. Games – the power of AS3 has brought Flash to the world of digital entertainment. At last it is possible to focus on the idea of your game rather than on how to improve the laggy experience. One thing that is still missing – right click functionality. We had this forever in desktop games, now it is time to let your casual RTS, RPG and FPS creations conquer the web.

2. User Experience – 2 buttons are better than 1. Every experimentalist's dream is to be able to have more input options, not just one button. I can bet someone would soon create a stunning interface using this new functionality

3. RIA – Rich Internet Applications. My clients are often asking if it is possible to remove embeded Flash Player menus from their applications and replace them with their company’s branding stuff.

And the answer is : YES! You can hack it to use custom right-click functionality in Flash and Flex.

Here is the demo and because you won't be able to right click it to View the Sources :) here they are

Javascript source code looks like this:

var RightClick = {
	init: function () {
		this.FlashObjectID = "RightClickDemo";
		this.FlashContainerID = "flashcontent";
		this.Cache = this.FlashObjectID;
		if(window.addEventListener){
			 window.addEventListener("mousedown", this.onGeckoMouse(), true);
			 document.oncontextmenu = function() { document.getElementById("RightClickDemo").rightClick(); }
		} else {
 
			document.getElementById(this.FlashContainerID).onmouseup = function() { document.getElementById(RightClick.FlashContainerID).releaseCapture(); }
			document.oncontextmenu = function(){ if(window.event.srcElement.id == RightClick.FlashObjectID) { return false; } else { RightClick.Cache = "nan"; }}
			document.getElementById(this.FlashContainerID).onmousedown = RightClick.onIEMouse;
		}
	},
	killEvents: function(eventObject) {
		if(eventObject) {
			if (eventObject.stopPropagation) { eventObject.stopPropagation(); }
			if (eventObject.preventDefault) { eventObject.preventDefault(); }
			if (eventObject.preventCapture) { eventObject.preventCapture(); }
		    if (eventObject.preventBubble) { eventObject.preventBubble(); }
		}
	},
	onGeckoMouse: function(ev) {
		return function(ev) {
		if (ev.button != 0) {
			RightClick.killEvents(ev);
			if(ev.target.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
                document.getElementById(RightClick.FlashObjectID).rightClick();
			}
			RightClick.Cache = ev.target.id;
		}
	  }
	},
	onIEMouse: function() {
        // stupid ie fix
        if (document.getElementById(RightClick.FlashObjectID + 'x'))
            document.getElementById(RightClick.FlashObjectID + 'x').id =  RightClick.FlashObjectID;
 
		if (event.button> 1) {
			if(window.event.srcElement.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
				RightClick.call();
			}
			document.getElementById(RightClick.FlashContainerID).setCapture();
			if(window.event.srcElement.id)
			RightClick.Cache = window.event.srcElement.id;
		}
	},
	call: function() {
		document.getElementById(RightClick.FlashObjectID).rightClick();
	}
}

On the Flash side is as simple as this code (AS3):

private function init() : void
{
    ExternalInterface.addCallback("rightClick", onRightClick);
}
 
private function onRightClick():void
{
    var mx:int = stage.mouseX;
    var my:int = stage.mouseY;
 
    if(my > 0 && my < stage.stageHeight && mx > 0 && mx < stage.stageWidth)
    {
        // show a custom context menu or do someting here
    }

On Opera this will not work, the browser forces the context menu to appear and blocks mouse events by default.

Few things you shouldn't forget to make this work

- 2 extra parameters you have to add to the flash object in your html
menu="false"
wmode="opaque"

- add to the body onload event RightClick.init(); function

Note: If you download the sources, you'll see in the html that the "object" tag has an extra 'x' character in the id. that's important to make it work in ie.


Comments (0) Trackbacks (1)
  1. Good tip! But I also found out that this doesn’t work for safari based browsers either and I’m searching for a way in Webkit to disable the right click. If you have any ideas, please let me know.

    Cheers!

  2. Yes, I know some browsers don’t allow context menus. But not only for flash, they don’t allow the javascript to catch the DOM event, so no custom context menu in anything. In firefox 3.0.7 is explicitly disabled but you can enable it from about:config by changing dom.event.contextmenu.enabled to true. I’m sure safari has it’s own hack. I’ll look into it and update the script.

  3. Yah, I’ve been looking and trying to find a hack forever, so I’ll be interested to see if you can find anything.

  4. [riffly_video]1C4D5CF42A0411DE933FC94D49680BD4[/riffly_video]

  5. Hi,

    that’s great to do this :)
    but when i am following your instructions it dosen’t work.
    When i make a right click nothing appear on my screnn.

    Something is missing somewhere, perhaps in my *.swf file.
    But i have the same code.

  6. @Black Shadow
    Is my demo working for you ? If yes, then you missed someting. Either in javascript or in as. You can download the sources from the link in the post and check it out. If no, then it must be the browser. I saw that safari doesn’t allow js to catch the rightclick event so from there … everything gets messy and somehow impossible. If you’re using Firefox and it’s still not working, check out my reply to malkomalko. You can enable the DOM context menu event in firefox. Let me know how it works for you. Cheers

  7. @malkomalko
    @Black Shadow

    k, i think i found what was wrong in Safari that it didn’t work. I’ve updated the script and tested on safari 4, firefox 3.5, chrome 2.0 and i’m proud to say it works (yeeey)!

  8. I quite agree with ADM about the 3 reasons, especially the 3rd one. Adobe should really have some actions on its Flash player or Flex SDK.

  9. Hello Admin and thanks a lot for your quick answer :) but Still not working :( in my PC.

    When i am tring your DEMO no problem on FF 3.0 :) but not work on IE 7.0.5. :(

    And when make it. It dosent’ work on FF too.
    I am using your AS3 code on flex (flash do not work too (bad luck for me)= and compile it. After i am using your JS code and replace all contents that was created by flex and execute it in FF. Still not working.

    I check out the error consol and have this result : http://blog.another-d-mention.ro/stuff/rightclick/RightClickDemo.html

    Hope so can help you to find what’s wrong. Your demo is working but when i am trying my self with a copy-paste source code and compile. It would be not :(

    Thanks

  10. @Black Shadow
    is your swf called RightClickDemo.swf ? Check your elements ids there and change as needed. And as I see in your jpg there, you’re running the html localy (as in file:///c:/documents and settings/…….) and that will not allow ExternalInterface to work. If you have a debug player you’ll see an error like: SecurityError: Error #2060: Security sandbox violation: ExternalInterface caller file:///C:/Documents and ……
    I’ve sent you an email with my yahoo id. We can discuss more there. Cheers

  11. There is another important reason for doing this:

    4) Flash context menu is buggy and poorly implemented

    o – press left mouse button, right click, release left mouse button, press escape – flash still thinks left mouse button is down until you click again

    o – there is no event fired for select all – I need to know this

    o – there is no event fired for escape when context menu is up

    o – aborting a current mouse process can be tricky when context menu is coming up

    o – since you cannot spawn a system menu on left click, the look and feel of your custom menu will most likely not match that of the system menu. not good

    I was thinking of using this to trap the right click if the swf was busy doing other mouse activity, otherwise, let the context menu come up

    So your solution works pretty well, but it means the swf wmode must be opaque which is slower than window wmode. Gee I hate to slow down flash even more lol There are other opaque wmode problems as well.

    I modified your code abit for IE. When you do a setCapture in onIEMouse, this causes mouse activity to stop in the swf. So in onIEMouse, after I do the setCapture, I do a setTimeout (“releaseMouse”,0); whichs releases the capture. This also prevents the context menu and also allows mouse messages to continue in the swf. e.g. I might have the left button down doing something, and I want the right click to have no effect and continue receiving mouse messages even if the right button is still down.

    Basically I am choosing not to do this at this time because of decreased performance, but pretty cool nevertheless.

    Don

  12. Sorry, typing error, should be: setTimeout (“releaseMouse()”,0);

  13. @DonMoir
    you don’t have to spawn a custom menu that looks like the system menu. you will do one that match your application skin or no context menu at all. just use the right click for extended functionality of the mouse (in case of a game)

  14. Yeah clearly you would match your skin. Without trapping right click, you possibly have two different menu styles coming up which is goofy and possibly confusing to the user. This is just another thing in the list of things wrong with the flash context menu.

  15. Tried this in Safari 4/Mac OS 10.4, and it didn’t work. Works great in Firefox and in all the XP browsers I’m running (IE, FF, Chrome). Unfortunately, since the client for this particular project is Apple, I don’t think I can tell them not to use Safari. Any ideas on how to implement this for Safari 4?

  16. @DavidC
    I have Safari 4.0.4 (531.21.10). Just installed it and seems to work just fine. But again, this is Windows XP. What may be different in Mac Safari, I really don’t know and I don’t own a mac to test it. But I’m sure it’s just a javascript issue that you can fix if you give it 30 minutes

  17. Hi,
    Is it wotking only with wmode opaque? what about GPU or direct modes

    Thanks

  18. It works well in IE, but there is some problem with input method when I want to input words with non-english letters in Firefox.How to solve this problem?

    (I am so frustrated, I have implemented right-click menu according to your method, but I find this problem now, since I am from China, I need to input Chinese definitly)

  19. Hi, I tried with firefox 3.6.3 , am not able to see the context menu. Also its working fine in IE. any clues?

  20. @Ajo Paul
    also the dom.contextmenu event is set to true in firefox about:config

  21. Hi ,
    Can you please tell me how to make it work for Opera browser. As i m using the same code it works well for others except Opera. Any solution for this if you have .

    VK

  22. hi,
    how can i give a context menu for components differently,
    what i meant to say is ,for eg;If i have two buttons in my application when i right click on the button it should display
    that button specified data.i dont want common context menu for entire application.could you please suggest me…..
    thank in advance

  23. @ BlackShadow
    @ Admin

    Have you found what’s wrong with BlackShadow’s issue ?
    I have the exact same problem : the demo works fine but when I download source and import them it doesn’t work anymore -> nothing happens when I right click and there is no stack in the debbuger…

  24. I have just tried on Chrome it works fine…
    (I have of course changed the dom.event.contextmenu.enabled to true in FF but still nothing…)

  25. I have had already edited the security sand box configuration file (the .cfg file) long ago because I had faced this problem with externalInterface.
    Also, I currently have another project on which Js and Flex are discussing through externalInterface without problem.
    Do you have any other lead on this curious issue ?

    Thanks a lot for your reply and by the way very interesting blog ;) !

    • try some debugging. see if the javascript function catches the click event and then if flash gets the E.I. message from javascript. somewhere along this way goes wrong

      • In debug mode, the flex function onRightClick() is never called so I tried firebug for debugging the Js and an error appears when I right click :

        “document.getElementById(“RightClickDemo”).rightClick is not a function”

        (line 37 in the script tag in index.template.html)

        • then is because you renamed the movie id in page, it document.getElementById(‘RightClickDemo’) returns nothing

          • :) no i didn’t rename it, i have just mistaken the line number, sorry :
            “document.getElementById(“RightClickDemo”).rightClick is not a function”
            is line 16
            and this one :
            “document.getElementById(RightClick.FlashObjectID).rightClick is not a function”
            line 37

            each right click triggers these two errors in firebug

          • Ok I figured out what the problem was, if it can help anyone ;) :

            Depending on your navigator (and on your navigator version) the html is read from top to bottom or from bottom to top. The problem here was that both the and the containing the flash had the same id “RightClickDemo” (which I hadn’t change btw :) ) and in one case (with FF) the rightClick() was called on the object rather than on the flash itself…
            To fix this I just gave another id to the object id=”${application}_o” this way I am sure that the function rightClick is called on the flash !

            Anyway thanks a lot for the component and the help !

  26. Also the weird thing is that, after I left click once, I no longer have the line 16 error on a right click

  27. hi very nice solution. I use swfobject.embedSWF() method to embed swf so i can’t use tag. So can u please tell me how to set id in that????

    In your example you have set RightClickDemo on embed tag and RightClickDemox on object tag. So how to set these 2 different id using swfobject.embedSWF() method…..

    Please help me…
    Regards

  28. Many thanks! That really works.

  29. hi
    can you explain why you add x to the object id
    i’m trying to use this solution with flex 4 but it doesn’t work on IE
    thanks

  30. Hi,

    Thanks for giving such a beautiful code.

    I had implemented the code for our application.The right click functionality is applying for the whole application.

    But our requirement is, we need to apply right click functionlaity specific to a datagrid custom component placed in the main Application file.

    Can anyone please help me where i need to change the code to achieve my requirement?

    • no need to change the javascript code. all you have to do is in actionscript. you know the cursor position and you know the position of your grid and the width and height of it. so you can determine the cell the click was made on. you have to improvise because there is no out of the box solution.

  31. Hi, great code!

    It works great in FF and Chrome but im IE 8 i get javascript error at line 19:

    “document.getElementById(…)’ is null or not an object”

    Any idea?? Please..

  32. I found a Customizing Flash Context Menu Using AS3 at http://www.as3tutorial.com, it’s easy to new beginners.

  33. Can i do this using AS2????

  34. I tried your demo in Safari Version 5.0.2 (6533.18.5). It didnt work. The usual flex context menu showed up. I am able to get the code working in IE, Firefox and Chrome. Is it that the code wont work in safari 5 or is it something am missing?

  35. Hello,
    I had this all working with FireFox 3.6 and Flash Player 10.1, but after updating the flash player to 10.2 the built-in context menu is not disabled. This seems to only happen on Solaris. 10.2 on Windows seem fine. Has anyone seen this problem?

  36. Hello
    i have one doubt
    Rightclick context menu is working perfectly in FF,chrome,IE with Flex3
    but it is not working when i have used Flex 4
    is there any solution

    Thanks
    venkat

  37. hello

    i’m trying to use this code with FLEX 4 in IE
    and i can’t prevent context menu from appearing
    any suggestions?
    thanks

  38. I was able my app work OK on Flex 4.5.1 using a few tweaks:

    1. In the default index.template.html from my app, i´ve changed all ‘RightClickDemo’ to ‘${application}’. This way, when i build the app, the builder change this to the correct app name.
    2. I´ve added to object params the attributes params.menu = “false” and params.wmode = “opaque”.
    3. Following the example, i´ve added the actionscript code and worked 100%.

    Now i got no Rigth-click menu to meddle with my user experience…

    Nicely done example. Helped me a lot! Thanks.

  39. how would i completely disable the content menu in SWF objects from others
    so ones where i don’t have any control over waht is done IN the SWF?
    (i’m integrating some SWF objects in HTA for my kid, so he can only acces that specific item from his special menu (shell replacement) on locked-down account)

    • well, nothing is done in the SWF. you can’t completely remove the context menu from the flash. the trick is to overlay it in html and catch the mouse click event there and prevent it from going to the flash movie.

  40. I tried this and it works fine in chrome. However I need it working in IE, I’m using IE9 and the context-menu of IE appears. Also the onRightClick function doesn’t get called in IE. What can I do about this? I really need it working in IE9.

    • I got it to work now.
      I´ve replaced each ‘RightClickDemo’ with ‘${application}’. I also put in the body-tag: oncontextmenu=”return false;”
      Now it works with IE too for some reason.

  41. How can you see on which list-item you clicked in this custom menu?
    I’m trying to add eventlisteners to each of the objects, but I don’t know how to get to the objects.

  42. I tried this on Safari 6.0 on an Intel-based Mac (2012) and it works just fine.

  43. hi… i tried this code run in IE 9 but in not working in firefox 21…
    i tried debug from firebug but i can’t find the error…
    its say “uncaught exception: Error in Actionscript. Use a try/catch block to find error.”
    any suggestion??


Reply

( Cancel )

CommentLuv badge

*