The Inbox: Morphic-mt.755.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Morphic-mt.755.mcz

commits-2
Marcel Taeumel uploaded a new version of Morphic to project The Inbox:
http://source.squeak.org/inbox/Morphic-mt.755.mcz

==================== Summary ====================

Name: Morphic-mt.755
Author: mt
Time: 26 January 2015, 3:33:59.723 pm
UUID: 2d4a39f5-5d85-d84e-bb0a-0d82257dd6c7
Ancestors: Morphic-mt.754

A keyboard event handler that supports multiple repeated key event processing. Normal #keyStroke: does not repeat if more than one key is pressed. Scenario: Multi-player Tetris. ^__^

The class comment includes instructions.

=============== Diff against Morphic-mt.754 ===============

Item was added:
+ Object subclass: #KeyboardEventHandler
+ instanceVariableNames: 'mutex pressedKeys longDelay shortDelay keyMap loop'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Morphic-Events'!
+
+ !KeyboardEventHandler commentStamp: 'mt 1/26/2015 15:30' prior: 0!
+ I allow for simulating repetition behavior of multiple "key strokes" because normal Squeak/OS cannot do that.
+
+ HOW TO USE
+ ---
+
+ 1) Subclass a morph, create an instance of me, give me a #keyMap, and call #startLoop, e.g. in #intoWorld:.
+ 2) Overwrite #handleKeyDown: and #handleKeyUp: and pass the events to me via #keyDown: resp. #keyUp:.
+ 2a) Call #value on the return value of #keyDown: if not nil to process the first call back immediately.
+ 3) Don't forget to call #stopLoop in, e.g., #outOfWorld: of your morph.
+
+ You can play around with #delay: and #rate: .!

Item was added:
+ ----- Method: KeyboardEventHandler>>delay (in category 'accessing') -----
+ delay
+
+ ^ longDelay!

Item was added:
+ ----- Method: KeyboardEventHandler>>delay: (in category 'accessing') -----
+ delay: milliseconds
+ "Time between first stroke and repetition."
+
+ mutex critical: [longDelay := milliseconds].!

Item was added:
+ ----- Method: KeyboardEventHandler>>fire: (in category 'running') -----
+ fire: keyValue
+
+ (keyMap at: keyValue ifAbsent: [])
+ ifNotNil: [:callback | WorldState addDeferredUIMessage: callback].!

Item was added:
+ ----- Method: KeyboardEventHandler>>initialize (in category 'initialization') -----
+ initialize
+
+ super initialize.
+
+ mutex := Mutex new.
+ pressedKeys := IdentityDictionary new.
+ longDelay := 200. "ms"
+ shortDelay := 20. "ms"!

Item was added:
+ ----- Method: KeyboardEventHandler>>keyDown: (in category 'event handling') -----
+ keyDown: evt
+ "Returns the callback if any. Caller has to ensure immediate fire!!"
+
+ | result |
+ result := nil.
+
+ mutex critical: [
+ pressedKeys at: evt keyValue ifAbsentPut: [
+ result := keyMap at: evt keyValue ifAbsent: [].
+ Time millisecondClockValue + longDelay]].
+
+ ^ result!

Item was added:
+ ----- Method: KeyboardEventHandler>>keyMap (in category 'accessing') -----
+ keyMap
+
+ ^ keyMap!

Item was added:
+ ----- Method: KeyboardEventHandler>>keyMap: (in category 'accessing') -----
+ keyMap: aKeyMap
+ "Maps actual key values to callbacks."
+
+ mutex critical: [keyMap := aKeyMap copy].!

Item was added:
+ ----- Method: KeyboardEventHandler>>keyUp: (in category 'event handling') -----
+ keyUp: evt
+
+ mutex critical: [
+ pressedKeys removeKey: evt keyValue ifAbsent: [] ].!

Item was added:
+ ----- Method: KeyboardEventHandler>>process (in category 'running') -----
+ process
+ "Look for callbacks to fire."
+
+ mutex critical: [
+ Time millisecondClockValue in: [:ms |
+ pressedKeys associationsDo: [:assoc |
+ ms >= assoc value ifTrue: [
+ self fire: assoc key.
+ assoc value: ms + shortDelay]]]].!

Item was added:
+ ----- Method: KeyboardEventHandler>>rate (in category 'accessing') -----
+ rate
+
+ ^ 1000 // shortDelay!

Item was added:
+ ----- Method: KeyboardEventHandler>>rate: (in category 'accessing') -----
+ rate: strokesPerSecond
+
+ mutex critical: [shortDelay := 1000 // strokesPerSecond].!

Item was added:
+ ----- Method: KeyboardEventHandler>>startLoop (in category 'running') -----
+ startLoop
+
+ self stopLoop.
+
+ loop := [
+ | delay |
+ delay := Delay forMilliseconds: 8.  
+ [ self process. delay wait ] repeat ] fork.!

Item was added:
+ ----- Method: KeyboardEventHandler>>stopLoop (in category 'running') -----
+ stopLoop
+
+ loop ifNotNil: #terminate.
+ loop := nil.!