//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package { import flash.display.DisplayObject; import flash.events.Event; import flash.events.FocusEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.events.StatusEvent; import flash.geom.Point; import flash.net.LocalConnection; import flash.utils.describeType; import flash.utils.getQualifiedClassName; import mx.core.IDeferredInstantiationUIComponent; import mx.core.IUIComponent; import mx.managers.SystemManager; import mx.core.mx_internal; use namespace mx_internal; [Mixin] /** * Tries to show location and target path of mouse */ public class MouseSnifferRemote { public function MouseSnifferRemote() { } public static function init(root:Object):void { document = root; connection = new LocalConnection(); connection.allowDomain("*"); connection.addEventListener(StatusEvent.STATUS, statusHandler); // Turn on only if the SnifferRemoteClient app's checkbox // for this item is checked. connection.send("_MouseSniffer", "toggleSniffersEnabled"); mousecommandconnection = new LocalConnection(); mousecommandconnection.allowDomain("*"); mousecommandconnection.client = MouseSnifferRemote; mousecommandconnection.connect("_MouseSnifferCommands"); } private static function statusHandler(event:Event):void { } /** * @private * The document containing a reference to this object */ private static var document:Object; /** * @private * The local connection to the remote client */ private static var connection:LocalConnection; private static var mousecommandconnection:LocalConnection; public static function enableSniffer():void { //trace("MouseSnifferRemote enabled"); document.stage.addEventListener(MouseEvent.CLICK, uberListener, true); document.stage.addEventListener(MouseEvent.DOUBLE_CLICK, uberListener, true); document.stage.addEventListener(MouseEvent.MOUSE_DOWN, uberListener, true); document.stage.addEventListener(MouseEvent.MOUSE_MOVE, uberListener, true); document.stage.addEventListener(MouseEvent.MOUSE_OUT, uberListener, true); document.stage.addEventListener(MouseEvent.MOUSE_OVER, uberListener, true); document.stage.addEventListener(MouseEvent.MOUSE_UP, uberListener, true); document.stage.addEventListener(MouseEvent.MOUSE_WHEEL, uberListener, true); document.stage.addEventListener(MouseEvent.ROLL_OUT, uberListener, true); document.stage.addEventListener(MouseEvent.ROLL_OVER, uberListener, true); } public static function disableSniffer():void { //trace("MouseSnifferRemote disabled"); document.stage.removeEventListener(MouseEvent.CLICK, uberListener, true); document.stage.removeEventListener(MouseEvent.DOUBLE_CLICK, uberListener, true); document.stage.removeEventListener(MouseEvent.MOUSE_DOWN, uberListener, true); document.stage.removeEventListener(MouseEvent.MOUSE_MOVE, uberListener, true); document.stage.removeEventListener(MouseEvent.MOUSE_OUT, uberListener, true); document.stage.removeEventListener(MouseEvent.MOUSE_OVER, uberListener, true); document.stage.removeEventListener(MouseEvent.MOUSE_UP, uberListener, true); document.stage.removeEventListener(MouseEvent.MOUSE_WHEEL, uberListener, true); document.stage.removeEventListener(MouseEvent.ROLL_OUT, uberListener, true); document.stage.removeEventListener(MouseEvent.ROLL_OVER, uberListener, true); } public static var propLists:Object = new Object(); private static function uberListener(event:MouseEvent):void { var target:String = findPath(event.target); var pt:Point = new Point(event.stageX, event.stageY); var obj:Object = document.document; var s:String = target; var dot:int = s.indexOf("."); var info:Object = new Object(); if (dot != -1) { var pieces:Array = s.split("."); for (var i:int = 0; i < pieces.length; i++) { s = pieces[i]; if (s != null && s.indexOf("getChildAt(") == 0) { s = s.substring(11); s = s.substring(0, s.length - 1); obj = obj.getChildAt(parseInt(s)); } else { if (obj!=null && s != null && s in obj) obj = obj[s]; else { // couldn't find the piece so document chain is broken. // Containers as item renderers break this target = ""; for (var j:int = 0; j < i; j++) { target += pieces[j]; if (j < i - 1) target += "." } break; } } } } else if (s.length && s.indexOf(" ") == -1) obj = obj[s]; if (obj != null) pt = obj.globalToLocal(pt); if (target == null || target == ""){ //connection.send("_MouseSniffer", "appendLog", "Mouse", "stage: " + pt.x + "," + pt.y + " stage: " + event.stageX + "," + event.stageY); info.dataSource = "Mouse"; info.target = "stage: " + pt.x + "," + pt.y + " stage: " + event.stageX + "," + event.stageY; info.eventName = ""; info.event = ""; connection.send("_MouseSniffer", "appendLog", info); }else{ //connection.send("_MouseSniffer", "appendLog", "Mouse", target + " " + pt.x + "," + pt.y + " stage: " + event.stageX + "," + event.stageY); info.dataSource = "Mouse"; info.target = target + " " + pt.x + "," + pt.y + " stage: " + event.stageX + "," + event.stageY; info.eventName = ""; info.event = ""; connection.send("_MouseSniffer", "appendLog", info); } } private static function findPath(target:Object, name:String = ""):String { var s:String = target.toString(); var dot:int = s.indexOf("."); if (dot == -1) { if (target == document.document || target.parent == document.document) return name; } while (target) { if (target is IDeferredInstantiationUIComponent) { var targetName:String = target.id; // id of component in document if (target.id && target.id in target.document) { if (target.document[target.id] is Array) { var arr:Array = target.document[target.id]; for (var i:int = 0; i < arr.length; i++) { if (arr[i] == target) { targetName += "." + i; break; } } } name = (name == "") ? targetName : targetName + "." + name; return findPath(target.document, name); } // MXML component has id in parent document if (target.id && target.document == target) { name = (name == "") ? target.id : target.id + "." + name; return findPath(target.parent.document, name); } } if (target.parent == document.document) break; if (target.parent is SystemManager) { // must be a popup if (target is IUIComponent) { s = findPropertyInOwner(target) if (s) { name = (name == "") ? s : s + "." + name; target = target.owner; continue; } } var index:int = document.document.systemManager.rawChildren.getChildIndex(target as DisplayObject); s = "systemManager.rawChildren.getChildAt(" + index + ")"; name = (name == "") ? s : s + "." + name; return name; } target = target.parent; } return "no component with id under mouse"; } private static function findPropertyInOwner(target:Object):String { var owner:Object = target.owner; var className:String = getQualifiedClassName(owner); var propList:XMLList = propLists[className]; if (!propList) { var dt:XML = describeType(owner); propList = dt..accessor.(@type != "Number" && @type != "String" && @type != "int" && @type != "Boolean" && @type != "Array" && @type != "Object" && @type != "Class" && @access != "writeonly") + dt..variable.(@type != "Number" && @type != "String" && @type != "int" && @type != "Boolean" && @type != "Array" && @type != "Object" && @type != "Class"); propLists[className] = propList; } var n:int = propList.length(); for (var i:int = 0; i < n; i++) { var propName:String = propList[i].@name.toString(); if (owner[propName] == target) return propName; } return null; } } }