From 002f0d1309e41cb7f0a8743256a580b05d1c7c2d Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Fri, 30 Nov 2007 19:17:02 +0000 Subject: [PATCH] So, key events are only dispatched on frames, and it seems that those happen after timer events in the flash player. What was happening was that a KEY_UP event was coming in so long after the initial KEY_DOWN, that this code would think that the key was being held down even when not. So instead we wait until we actually see a 2nd KEY_DOWN event, at which point we may need to dispatch that event right away, or we may need to wait a bit if the limitRate is higher than the elapsed time between the two events. Now also there is a Timer for each key being held down. To top it all off, if you hold a key and then lose focus then this will continue to fire, so it's going to need yet more complication to fix that. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@358 ed5b42cb-e716-0410-a449-f6a68f950b19 --- .../com/threerings/flash/KeyRepeatLimiter.as | 81 +++++++++++-------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/src/as/com/threerings/flash/KeyRepeatLimiter.as b/src/as/com/threerings/flash/KeyRepeatLimiter.as index a6641f21..7ce2201f 100644 --- a/src/as/com/threerings/flash/KeyRepeatLimiter.as +++ b/src/as/com/threerings/flash/KeyRepeatLimiter.as @@ -29,6 +29,8 @@ import flash.events.TimerEvent; import flash.utils.Dictionary; import flash.utils.Timer; +import flash.utils.getTimer; + /** * A very simple class that adapts the KeyboardEvents generated by some source and altering * (or blocking) the key repeat rate. @@ -46,14 +48,10 @@ public class KeyRepeatLimiter extends EventDispatcher public function KeyRepeatLimiter (source :IEventDispatcher, limitRate :int = 0) { _source = source; + _limitRate = limitRate; _source.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown); _source.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp); - - if (limitRate > 0) { - _timer = new Timer(limitRate); - _timer.addEventListener(TimerEvent.TIMER, handleTimerEvent); - } } /** @@ -64,39 +62,50 @@ public class KeyRepeatLimiter extends EventDispatcher _source.removeEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown); _source.removeEventListener(KeyboardEvent.KEY_UP, handleKeyUp); - _down = new Dictionary(); - _keysDown = 0; - if (_timer != null) { - _timer.stop(); + // shut down any timers + for each (var val :* in _down) { + if (val is Array) { + ((val as Array)[0] as Timer).stop(); + } } + _down = new Dictionary(); } protected function handleKeyDown (event :KeyboardEvent) :void { - if (undefined === _down[event.keyCode]) { - _keysDown++; - _down[event.keyCode] = event.clone(); + var oldVal :* = _down[event.keyCode]; + if (oldVal === undefined) { + _down[event.keyCode] = (_limitRate > 0) ? getTimer() : 0; - // maybe start the timer if we need to - if (_timer != null && !_timer.running) { - _timer.reset(); - _timer.start(); + } else if ((oldVal is Number) && _limitRate > 0) { + var timeUntilRepeat :Number = _limitRate - (getTimer() - Number(oldVal)); + + var t :Timer = new Timer((timeUntilRepeat <= 0) ? _limitRate : timeUntilRepeat); + t.addEventListener(TimerEvent.TIMER, handleTimerEvent); + _down[event.keyCode] = [ t, event ]; + t.start(); + if (timeUntilRepeat > 0) { + // don't dispatch this event, wait for our first repeat time + return; } - // only dispatch if we're not limiting this key - dispatchEvent(event); + } else { + // eat the event + return; } + + // otherwise, dispatch the event + dispatchEvent(event); } protected function handleKeyUp (event :KeyboardEvent) :void { - if (undefined !== _down[event.keyCode]) { - delete _down[event.keyCode]; - _keysDown--; - - if (_timer != null && _keysDown == 0) { - _timer.stop(); + var oldVal :* = _down[event.keyCode]; + if (oldVal !== undefined) { + if (oldVal is Array) { + ((oldVal as Array)[0] as Timer).stop(); } + delete _down[event.keyCode]; } // always dispatch an up @@ -105,9 +114,21 @@ public class KeyRepeatLimiter extends EventDispatcher protected function handleTimerEvent (event :TimerEvent) :void { - // dispatch any saved key events - for each (var keyEvent :KeyboardEvent in _down) { - dispatchEvent(keyEvent); + // dispatch the key event associated with this timer + for each (var val :* in _down) { + if (val is Array) { + var arr :Array = val as Array; + var timer :Timer = arr[0] as Timer; + if (timer == event.target) { + if (timer.delay != _limitRate) { + timer.reset(); + timer.delay = _limitRate; + timer.start(); + } + dispatchEvent(arr[1] as KeyboardEvent); + break; + } + } } } @@ -117,10 +138,6 @@ public class KeyRepeatLimiter extends EventDispatcher /** Tracks whether a key is currently being held down. */ protected var _down :Dictionary = new Dictionary(); - /** How many keys are currently down? */ - protected var _keysDown :int; - - /** The timer generating key repeats, if any. */ - protected var _timer :Timer; + protected var _limitRate :int; } }