Skip to content

Commit 74c27c8

Browse files
committed
fix multiple frame/key listeners causing multiple trigger fires
1 parent 37fc795 commit 74c27c8

2 files changed

Lines changed: 37 additions & 6 deletions

File tree

wurst/closures/ClosureFrames.wurst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,23 @@ public function framehandle.onSpriteAnimUpdate(FrameHandleListener listener) ret
8080
return addListenerForFrame(listener, this, FRAMEEVENT_SPRITE_ANIM_UPDATE)
8181

8282
function addListenerForFrame(FrameHandleListener listener, framehandle frame, frameeventtype eventType) returns FrameHandleListener
83-
FRAMEHANDLE_TRIGGER.registerFrameEvent(frame, eventType)
8483
listener.frame = frame
8584
listener.eventType = eventType
8685
let id = frame.getHandleId()
8786
let first = FRAME_MAP.get(id)
87+
// Register (frame, eventType) on the shared trigger only ONCE. onEvent() already fans a single
88+
// trigger fire out to every listener in the list, so re-registering on each added listener makes
89+
// the trigger fire once PER registration: a frame with two CONTROL_CLICK listeners then runs its
90+
// click handler twice (which silently toggled controls back, e.g. a checkbox that never unchecks).
91+
// Skip re-registration when this frame already has a listener for the same event type.
92+
var alreadyRegistered = false
93+
var cursor = first
94+
while cursor != null
95+
if cursor.eventType == eventType
96+
alreadyRegistered = true
97+
cursor = cursor.next
98+
if not alreadyRegistered
99+
FRAMEHANDLE_TRIGGER.registerFrameEvent(frame, eventType)
88100
if first != null
89101
first.prev = listener
90102
listener.next = first

wurst/closures/ClosureKeyPresses.wurst

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,25 @@ import HashMap
2828

2929
constant KEY_TRIGGER = CreateTrigger()..addAction(function onEvent)
3030
constant KEY_MAP = new HashMap<int, KeyPressListener>
31-
31+
32+
// Tracks which (player, key, metaKey, onKeyDown) combos are already registered on KEY_TRIGGER, so a
33+
// second listener for the same combo does NOT register the event twice on one trigger (which fires the
34+
// trigger, and therefore every matching listener, twice per key press). Keyed by key handle id, then by
35+
// a small composite of player id + meta + up/down. Never cleared: WC3 has no per-event unregister, so
36+
// "ever registered" equals "currently registered".
37+
constant KEY_REGISTERED = new HashMap<int, HashMap<int, bool>>
38+
39+
function registerKeyOnce(player whichPlayer, oskeytype key, OSKEY_META metaKey, bool onKeyDown)
40+
let keyId = key.getHandleId()
41+
var combos = KEY_REGISTERED.get(keyId)
42+
if combos == null
43+
combos = new HashMap<int, bool>
44+
KEY_REGISTERED.put(keyId, combos)
45+
let combo = whichPlayer.getId() * 64 + metaKey.toInt() * 2 + (onKeyDown ? 1 : 0)
46+
if not combos.has(combo)
47+
combos.put(combo, true)
48+
KEY_TRIGGER.registerPlayerKeyPress(whichPlayer, key, metaKey, onKeyDown)
49+
3250

3351
/* CLOSURES */
3452

@@ -42,9 +60,9 @@ public function onKeyRelease(oskeytype key, KeyPressListener listener) returns K
4260
return onKeyPress(key, OSKEY_META.NONE, false, listener)
4361

4462
public function onKeyPress(oskeytype key, OSKEY_META metaKey, bool onKeyDown, KeyPressListener listener) returns KeyPressListener
45-
for i = 0 to bj_MAX_PLAYERS
63+
for i = 0 to bj_MAX_PLAYERS - 1
4664
if players[i].isIngame()
47-
KEY_TRIGGER.registerPlayerKeyPress(players[i], key, metaKey, onKeyDown)
65+
registerKeyOnce(players[i], key, metaKey, onKeyDown)
4866
return registerListener(listener, key, metaKey, onKeyDown)
4967

5068
public function onKeyPress(player whichPlayer, oskeytype key, KeyPressListener listener) returns KeyPressListener
@@ -57,7 +75,7 @@ public function onKeyRelease(player whichPlayer, oskeytype key, KeyPressListener
5775
return onKeyPress(whichPlayer, key, OSKEY_META.NONE, false, listener)
5876

5977
public function onKeyPress(player whichPlayer, oskeytype key, OSKEY_META metaKey, bool onKeyDown, KeyPressListener listener) returns KeyPressListener
60-
KEY_TRIGGER.registerPlayerKeyPress(whichPlayer, key, metaKey, onKeyDown)
78+
registerKeyOnce(whichPlayer, key, metaKey, onKeyDown)
6179
return registerListener(listener, key, metaKey, onKeyDown)
6280

6381
function registerListener(KeyPressListener listener, oskeytype key, OSKEY_META metaKey, bool onKeyDown) returns KeyPressListener
@@ -106,4 +124,5 @@ abstract class KeyPressListener
106124
KEY_MAP.put(id, next)
107125
else if prev != null
108126
prev.next = next
109-
next.prev = prev
127+
if next != null
128+
next.prev = prev

0 commit comments

Comments
 (0)