Mostly kinda fixed up keyboard issues for EZGames.

They can add their keyboard listeners directly to the GameControl object
to receive global key events.

There are strange focus weirdnesses on the flex side- sometimes you have
focus with no focus highlight and sometimes you don't have focus and you
do have the highlight. Punting, rather than spending more hours on this.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@138 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Ray Greenwell
2007-01-06 01:44:05 +00:00
parent 3b08974f73
commit 00e2c45f01
4 changed files with 137 additions and 14 deletions
+52 -5
View File
@@ -4,6 +4,8 @@ import flash.errors.IllegalOperationError;
import flash.events.Event; import flash.events.Event;
import flash.events.EventDispatcher; import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.display.DisplayObject; import flash.display.DisplayObject;
@@ -20,6 +22,41 @@ public class EZGameControl extends EventDispatcher
populateProperties(event.userProps); populateProperties(event.userProps);
disp.root.loaderInfo.sharedEvents.dispatchEvent(event); disp.root.loaderInfo.sharedEvents.dispatchEvent(event);
setEZProps(event.ezProps); setEZProps(event.ezProps);
// set up our focusing click handler
disp.root.addEventListener(MouseEvent.CLICK, handleRootClick);
}
// documentation inherited
override public function addEventListener (
type :String, listener :Function, useCapture :Boolean = false,
priority :int = 0, useWeakReference :Boolean = false) :void
{
super.addEventListener(type, listener, useCapture, priority,
useWeakReference);
switch (type) {
case KeyboardEvent.KEY_UP:
case KeyboardEvent.KEY_DOWN:
if (hasEventListener(type)) { // ensure it was added
callEZCode("alterKeyEvents_v1", type, true);
}
}
}
// documentation inherited
override public function removeEventListener (
type :String, listener :Function, useCapture :Boolean = false) :void
{
super.removeEventListener(type, listener, useCapture);
switch (type) {
case KeyboardEvent.KEY_UP:
case KeyboardEvent.KEY_DOWN:
if (!hasEventListener(type)) { // once it's no longer needed
callEZCode("alterKeyEvents_v1", type, false);
}
}
} }
// from EZGame // from EZGame
@@ -240,11 +277,6 @@ public class EZGameControl extends EventDispatcher
callEZCode.apply(null, args); callEZCode.apply(null, args);
} }
override public function willTrigger (type :String) :Boolean
{
throw new IllegalOperationError();
}
override public function dispatchEvent (event :Event) :Boolean override public function dispatchEvent (event :Event) :Boolean
{ {
// Ideally we want to not be an IEventDispatcher so that people // Ideally we want to not be an IEventDispatcher so that people
@@ -285,6 +317,7 @@ public class EZGameControl extends EventDispatcher
o["messageReceived_v1"] = messageReceived_v1; o["messageReceived_v1"] = messageReceived_v1;
o["gameDidStart_v1"] = gameDidStart_v1; o["gameDidStart_v1"] = gameDidStart_v1;
o["gameDidEnd_v1"] = gameDidEnd_v1; o["gameDidEnd_v1"] = gameDidEnd_v1;
o["dispatchEvent_v1"] = dispatch;
} }
private function propertyWasSet_v1 ( private function propertyWasSet_v1 (
@@ -341,6 +374,20 @@ public class EZGameControl extends EventDispatcher
} }
} }
/**
* Internal method that is called whenever the mouse enters our root.
*/
protected function handleRootClick (evt :MouseEvent) :void
{
try {
if (evt.target.stage.focus != null) {
return;
}
} catch (err :SecurityError) {
}
callEZCode("focusContainer_v1");
}
/** /**
* Secret function to dispatch property changed events. * Secret function to dispatch property changed events.
*/ */
@@ -49,10 +49,10 @@ public class EZGamePanel extends VBox
_ezObj = (plobj as EZGameObject); _ezObj = (plobj as EZGameObject);
backend = new GameControlBackend(_ctx, _ezObj); backend = new GameControlBackend(_ctx, _ezObj);
_gameView = new GameContainer(cfg.configData); // TODO _gameView = new GameContainer(cfg.configData); // TODO?
_gameView.tabEnabled = true;
backend.setSharedEvents( backend.setSharedEvents(
Loader(_gameView.getMedia()).contentLoaderInfo.sharedEvents); Loader(_gameView.getMedia()).contentLoaderInfo.sharedEvents);
backend.setContainer(_gameView);
addChild(_gameView); addChild(_gameView);
} }
@@ -1,27 +1,55 @@
package com.threerings.ezgame.client { package com.threerings.ezgame.client {
import flash.display.InteractiveObject;
import flash.display.Loader; import flash.display.Loader;
import flash.geom.Rectangle;
import mx.core.mx_internal;
import mx.core.IFlexDisplayObject;
import mx.core.IInvalidating;
import mx.managers.IFocusManagerComponent; import mx.managers.IFocusManagerComponent;
import mx.skins.ProgrammaticSkin;
import com.threerings.util.MediaContainer; import com.threerings.util.MediaContainer;
// TODO: there are focus issues in here that need dealing with.
//
// 1) The focus rectangle is drawn at the wrong size in scrolling games
// 2) We can get focus without having the pink focus rectangle...
// 3) When the mouse leaves the flash player and returns, this
// damn thing doesn't seem to grip onto the focus.
//
public class GameContainer extends MediaContainer public class GameContainer extends MediaContainer
implements IFocusManagerComponent implements IFocusManagerComponent
{ {
public function GameContainer (url :String) public function GameContainer (url :String)
{ {
super(url); super(url);
tabEnabled = true; // turned off by Container
// focusRect = true; // we need the focus rect
} }
override public function setFocus () :void override protected function adjustFocusRect (obj :DisplayObject = null) :void
{ {
super.setFocus(); super.adjustFocusRect(obj);
if (systemManager.stage.focus == this) {
// TODO // TODO: this is probably all wrong
//systemManager.stage.focus = InteractiveObject(Loader(_media).content); var focusObj :IFlexDisplayObject =
systemManager.stage.focus = Loader(_media); IFlexDisplayObject(mx_internal::getFocusObject());
if (focusObj) {
var r :Rectangle = transform.pixelBounds;
focusObj.setActualSize(r.width - 2, r.height - 2);
focusObj.move(0, 0);
if (focusObj is IInvalidating) {
IInvalidating(focusObj).validateNow();
} else if (focusObj is ProgrammaticSkin) {
ProgrammaticSkin(focusObj).validateNow();
}
} }
} }
} }
@@ -5,6 +5,12 @@ import flash.errors.IllegalOperationError;
import flash.events.Event; import flash.events.Event;
import flash.events.EventDispatcher; import flash.events.EventDispatcher;
import flash.events.IEventDispatcher; import flash.events.IEventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.utils.IExternalizable; import flash.utils.IExternalizable;
import flash.utils.ByteArray; import flash.utils.ByteArray;
@@ -38,6 +44,9 @@ import com.threerings.ezgame.data.PropertySetListener;
import com.threerings.ezgame.data.UserCookie; import com.threerings.ezgame.data.UserCookie;
import com.threerings.ezgame.util.EZObjectMarshaller; import com.threerings.ezgame.util.EZObjectMarshaller;
/**
* Manages the backend of the game.
*/
public class GameControlBackend public class GameControlBackend
implements MessageListener, SetListener, PropertySetListener implements MessageListener, SetListener, PropertySetListener
{ {
@@ -59,6 +68,11 @@ public class GameControlBackend
disp.addEventListener("ezgameQuery", handleEZQuery); disp.addEventListener("ezgameQuery", handleEZQuery);
} }
public function setContainer (container :GameContainer) :void
{
_container = container;
}
public function shutdown () :void public function shutdown () :void
{ {
_ezObj.removeListener(this); _ezObj.removeListener(this);
@@ -76,6 +90,8 @@ public class GameControlBackend
{ {
// here we would handle adapting old functions to a new version // here we would handle adapting old functions to a new version
_ezDispatcher = (o["dispatchEvent_v1"] as Function);
_userFuncs = o; _userFuncs = o;
} }
@@ -121,6 +137,8 @@ public class GameControlBackend
o["endGame_v1"] = endGame_v1; o["endGame_v1"] = endGame_v1;
o["populateCollection_v1"] = populateCollection_v1; o["populateCollection_v1"] = populateCollection_v1;
o["getFromCollection_v1"] = getFromCollection_v1; o["getFromCollection_v1"] = getFromCollection_v1;
o["alterKeyEvents_v1"] = alterKeyEvents_v1;
o["focusContainer_v1"] = focusContainer_v1;
} }
public function setProperty_v1 ( public function setProperty_v1 (
@@ -342,6 +360,30 @@ public class GameControlBackend
playerIndex, listener); playerIndex, listener);
} }
public function alterKeyEvents_v1 (
keyEventType :String, add :Boolean) :void
{
if (add) {
_container.addEventListener(keyEventType, handleKeyEvent);
} else {
_container.removeEventListener(keyEventType, handleKeyEvent);
}
}
public function focusContainer_v1 () :void
{
_container.setFocus();
}
/**
* Handle key events on our container and pass them into the game.
*/
protected function handleKeyEvent (evt :KeyboardEvent) :void
{
// dispatch a cloned copy of the event, so that it's safe
_ezDispatcher(evt.clone());
}
/** /**
* Convenience function to get our name. * Convenience function to get our name.
*/ */
@@ -564,10 +606,16 @@ public class GameControlBackend
protected var _userListener :MessageAdapter = protected var _userListener :MessageAdapter =
new MessageAdapter(messageReceivedOnUserObject); new MessageAdapter(messageReceivedOnUserObject);
protected var _container :GameContainer;
protected var _ezObj :EZGameObject; protected var _ezObj :EZGameObject;
protected var _userFuncs :Object; protected var _userFuncs :Object;
/** The function on the EZGameControl which we can use to directly
* dispatch events to the user's game. */
protected var _ezDispatcher :Function;
protected var _gameData :GameData; protected var _gameData :GameData;
/** playerIndex -> callback functions waiting for the cookie. */ /** playerIndex -> callback functions waiting for the cookie. */