case
3Apr/0958

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.