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.! |
Free forum by Nabble | Edit this page |