2
votes

I use for my flash application external touch-input. Signals from touch panel I receive via TUIO library for as3 ( https://code.google.com/p/tuio-as3/ )

I have sometimes problem then TuioManager wrong detects object which must receive touch input.

private function getTopDisplayObjectUnderPoint(point:Point):DisplayObject {
    var targets:Array =  stage.getObjectsUnderPoint(point);
    var item:DisplayObject = (targets.length > 0) ? targets[targets.length - 1] : stage;

    if (this.touchTargetDiscoveryMode == TOUCH_TARGET_DISCOVERY_MOUSE_ENABLED) {
        while (targets.length > 0) {
            item = targets.pop() as DisplayObject;
            //ignore debug cursor/object/blob and send object under debug cursor/object/blob
            if ((item is ITuioDebugCursor || item is ITuioDebugBlob || item is ITuioDebugObject || item is ITuioDebugTextSprite) && targets.length > 0) {
                continue;
            }
            if (item.parent != null && !(item is InteractiveObject)) item = item.parent;
            if (item is InteractiveObject) {
                if ((item as InteractiveObject).mouseEnabled) return item;
            }
        }
        item = stage;
    }
    else if (this.touchTargetDiscoveryMode == TOUCH_TARGET_DISCOVERY_IGNORELIST) {
        while (targets.length > 0) {
            item = targets.pop();
            //ignore debug cursor/object/blob and send object under debug cursor/object/blob
            if ((item is ITuioDebugCursor || item is ITuioDebugBlob || item is ITuioDebugObject || item is ITuioDebugTextSprite) && targets.length > 0) {
                continue;
            }
            if (!bubbleListCheck(item)) return item;
        }
        item = stage;
    }

    return item;
}

I used this.touchTargetDiscoveryMode == TOUCH_TARGET_DISCOVERY_MOUSE_ENABLED.

This function does not use mouseChildren property.

For example, I use world map in fxg graphic and I want disable all its children: worldMap.mouseChildren = false;

But it works if I use system mouse input, but not for TUIO. Result of function getTopDisplayObjectUnderPoint will be one of child MovieClip. In trace I see hierarchy like as:

worldMap
    MovieClip
        ....
           MovieClip

Yes, I can set recursively all property mouseEnabled = false for children of worldMap. It can fix for only this problem, but not problem with wrong object selection in more global case.

I tried to modify this function and wrote two helper function:

private function isMouseChildrenEnabled(obj:DisplayObject):Boolean {
    if (obj.parent == null) {
        return true;
    }
    return obj.parent.mouseChildren && isMouseChildrenEnabled(obj.parent);
}

private function findMouseEnabledObject(obj:InteractiveObject):InteractiveObject
{
    if (obj.mouseEnabled && isMouseChildrenEnabled(obj))
        return obj;
    return obj.parent ? findMouseEnabledObject(obj.parent) : null;
}

private function getTopDisplayObjectUnderPoint(point:Point):DisplayObject {
    var targets:Array =  stage.getObjectsUnderPoint(point);
    var item:DisplayObject = (targets.length > 0) ? targets[targets.length - 1] : stage;

    if(this.touchTargetDiscoveryMode == TOUCH_TARGET_DISCOVERY_MOUSE_ENABLED){
        while(targets.length > 0) {
            item = targets.pop() as DisplayObject;
            //ignore debug cursor/object/blob and send object under debug cursor/object/blob
            if((item is ITuioDebugCursor || item is ITuioDebugBlob || item is ITuioDebugObject || item is ITuioDebugTextSprite) && targets.length > 0){
                continue;
            }
            if (item.parent != null && !(item is InteractiveObject)) item = item.parent;
            if (item is InteractiveObject) {
                var io:InteractiveObject = findMouseEnabledObject(item as InteractiveObject);
                if (io) return io;
            }
        }
        item = stage;
    } else if (this.touchTargetDiscoveryMode == TOUCH_TARGET_DISCOVERY_IGNORELIST) {
        while(targets.length > 0) {
            item = targets.pop();
            //ignore debug cursor/object/blob and send object under debug cursor/object/blob
            if((item is ITuioDebugCursor || item is ITuioDebugBlob || item is ITuioDebugObject || item is ITuioDebugTextSprite) && targets.length > 0){
                continue;
            }
            if (!bubbleListCheck(item)) return item;
        }
        item = stage;
    }

    return item;
}

But after new fixes we have new bugs :( I see bug if I use flex drag drop. During drag drop flex shows dragged image and tuio detects wrong drop target. In trace stage.getObjectsUnderPoint() I see something like as:

[n] - image (mouseEnabled=true, mouseChildren=true)
   parent: embed_swf_drag_cursor... (mouseEnabled=false, mouseChildren=false)
      parent: application_systemManager... (mouseEnabled=true, mouseChildren=true)
          parent: stage
[n-1] - borderContainer (mouseEnabled=true, mouseChildren=true) - it is my drop target

In result I have systemManager as target, but I need BorderContainer.

How correct find enabled object for user input?

P.S. Tested on Linux and Windows flash players.

Update 13.11

I tried to write function which get enabled object under point:

private function getTopEnabledObject(object:DisplayObjectContainer, hitPoint:Point):InteractiveObject
{
    if (!object.mouseChildren)
        return  null;
    var child:DisplayObject;
    for (var i:int = object.numChildren - 1; i >= 0; i--)
    {
        child = object.getChildAt(i);
        if (child.visible && child is InteractiveObject && child.hitTestPoint(hitPoint.x, hitPoint.y, true))
        {
            if (child is DisplayObjectContainer)
            {
                var target:InteractiveObject = getTopEnabledObject(child as DisplayObjectContainer, hitPoint);
                if (target)
                    return target;
            }
            if ((child as InteractiveObject).mouseEnabled)
                return child as InteractiveObject; 
        }
    }
    return null;
}

It works slowly in 5-10 times. And I had crashes after many-many touches in short time.

1
How about event.target and event.currentTarget ? - Adrian Pirvulescu
We don't have events on this step. We try to find event target here. - lexus.pp

1 Answers

0
votes

The way you are doing it looks right. The only thing I would correct is that in isMouseChildrenEnabled you can stop at the first mouseChildren = false and return false.

If Flex adds an image of dragged object you will always get it as a top target. You have to code a special case for it.