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.
Related posts:
- Open and Save files to Desktop without going to Server
- Install Windows XP on your Asus Eee PC using a USB flash drive
- Create professional Flex components
- Communicate betwen C# and an embeded Flash application
- How to clone (duplicate) an object in ActionScript 3
Enjoy this article?
Categories
- How To's (7)
- Misc (34)
- Eee PC (2)
- Internet (7)
- Software (10)
- Stories for a IT Audience (7)
- Stuff (7)
- Programming (29)
- C# (2)
- CSS (4)
- Flex / ActionScript (15)
- Java (2)
- Java Script (4)
- Python (3)
Tags
Blogroll
- Aeroh’s Blog
- Evolverine
- Flash, Flex, news, fun and more …
- Flex, AIR and Rock&Roll
- Obiectiv Photo Studio
- Photography, photoshop
- Tee-bee, que ?
April 12th, 2009 - 14:48
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!
April 12th, 2009 - 17:30
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.
April 13th, 2009 - 05:15
Yah, I’ve been looking and trying to find a hack forever, so I’ll be interested to see if you can find anything.
April 15th, 2009 - 23:38
Play Video Comment
July 8th, 2009 - 14:11
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.
July 8th, 2009 - 14:19
@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
July 8th, 2009 - 14:53
@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)!
July 8th, 2009 - 17:20
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.
July 9th, 2009 - 10:37
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
July 9th, 2009 - 10:38
sorry here is the right link :
http://img440.imageshack.us/img440/5267/errorl.jpg
July 9th, 2009 - 10:49
@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
July 17th, 2009 - 13:11
its working gud thankz
October 24th, 2009 - 03:04
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
October 24th, 2009 - 08:19
Sorry, typing error, should be: setTimeout (“releaseMouse()”,0);
October 24th, 2009 - 09:48
@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)
October 24th, 2009 - 13:58
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.
February 4th, 2010 - 01:39
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?
February 4th, 2010 - 10:32
@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
February 23rd, 2010 - 16:13
Hi,
Is it wotking only with wmode opaque? what about GPU or direct modes
Thanks
March 12th, 2010 - 11:35
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)
April 14th, 2010 - 15:08
Hi, I tried with firefox 3.6.3 , am not able to see the context menu. Also its working fine in IE. any clues?
April 14th, 2010 - 15:12
@Ajo Paul
also the dom.contextmenu event is set to true in firefox about:config
April 30th, 2010 - 08:27
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
June 25th, 2010 - 06:28
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
July 8th, 2010 - 11:29
@ 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…
July 8th, 2010 - 11:33
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…)
July 8th, 2010 - 11:37
if you do try it locally be sure to place the build in a web server and test it from http://localhost/. It uses ExternalInterface and it won’t allow javascript to communicate with flash otherwise due to security issues.
July 8th, 2010 - 12:26
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
!
July 8th, 2010 - 12:38
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
July 8th, 2010 - 14:32
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)
July 8th, 2010 - 14:38
then is because you renamed the movie id in page, it document.getElementById(‘RightClickDemo’) returns nothing
July 8th, 2010 - 14:50
“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
July 8th, 2010 - 16:45
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 !
July 8th, 2010 - 15:20
Also the weird thing is that, after I left click once, I no longer have the line 16 error on a right click