The Inbox: Kernel-dtl.1340.mcz

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

The Inbox: Kernel-dtl.1340.mcz

commits-2
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-dtl.1340.mcz

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

Name: Kernel-dtl.1340
Author: dtl
Time: 15 September 2020, 10:28:36.703545 pm
UUID: d155f790-f808-4f68-ae73-3d98434f66d0
Ancestors: Kernel-ul.1339

Implement Sensor eventTimeNow for support of synthesized events. Eliminates the sometimes incorrect assumption that event time stamps must match the obsolete VM millisecond clock, and allows the Windows VM to consistently use native Windows event time stamps in the event queue.

=============== Diff against Kernel-ul.1339 ===============

Item was changed:
  Object subclass: #EventSensor
+ instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
- instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore'
  classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodeTable'
  poolDictionaries: 'EventSensorConstants'
  category: 'Kernel-Processes'!
 
  !EventSensor commentStamp: 'mt 12/13/2019 14:38' prior: 0!
  An EventSensor is an interface to the user input devices.
  There is at least one instance of EventSensor named Sensor in the system.
 
  EventSensor is a replacement for the earlier InputSensor implementation based on a set of (optional) event primitives. An EventSensor updates its state when events are received so that all state based users of Sensor (e.g., Sensor keyboard, Sensor leftShiftDown, Sensor mouseButtons) will work exactly as before, by moving the current VM mechanisms into EventSensor itself. An optional input semaphore is part of the new design.
 
  For platforms that support true asynchronous event notification, the semaphore will be signaled to indicate pending events.
  On platforms that do not support asynchronous notifications about events, the UI will have to poll EventSensor periodically to read events from the VM.
 
  Instance variables:
  mouseButtons <Integer> - mouse button state as replacement for primMouseButtons
  mousePosition <Point> - mouse position as replacement for primMousePt
  keyboardBuffer <SharedQueue> - keyboard input buffer
  interruptKey <Integer> - currently defined interrupt key
  interruptSemaphore <Semaphore> - the semaphore signaled when the interruptKey is detected
  eventQueue <SharedQueue> - an optional event queue for event driven applications
  inputSemaphore <Semaphore>- the semaphore signaled by the VM if asynchronous event notification is supported
  lastEventPoll <Integer> - the last millisecondClockValue at which we called fetchMoreEvents
  hasInputSemaphore <Boolean> - true if my inputSemaphore has actually been signaled at least once.
 
  Class variables:
  ButtonDecodeTable <ByteArray> - maps mouse buttons as reported by the VM to ones reported in the events.
  KeyDecodeTable <Dictionary<SmallInteger->SmallInteger>> - maps some keys and their modifiers to other keys (used for instance to map Ctrl-X to Alt-X)
  InterruptSemaphore <Semaphore> - signalled by the the VM and/or the event loop upon receiving an interrupt keystroke.
  InterruptWatcherProcess <Process> - waits on the InterruptSemaphore and then responds as appropriate.
  EventPollPeriod <Integer> - the number of milliseconds to wait between polling for more events in the userInterruptHandler.
  EventTicklerProcess <Process> - the process that makes sure that events are polled for often enough (at least every EventPollPeriod milliseconds).
 
  Event format:
  The current event format is very simple. Each event is recorded into an 8 element array. All events must provide some SmallInteger ID (the first field in the event buffer) and a time stamp (the second field in the event buffer), so that the difference between the time stamp of an event and the current time can be reported.
 
  Currently, the following events are defined:
 
  Null event
  =============
  The Null event is returned when the ST side asks for more events but no more events are available.
  Structure:
  [1] - event type 0
  [2-8] - unused
 
  Mouse event structure
  ==========================
  Mouse events are generated when mouse input is detected.
  [1] - event type 1
  [2] - time stamp
  [3] - mouse x position
  [4] - mouse y position
  [5] - button state; bitfield with the following entries:
  1 - 2r001 yellow (e.g., right) button
  2 - 2r010 blue (e.g., middle) button
  4 - 2r100 red (e.g., left) button
  [all other bits are currently undefined]
  [6] - modifier keys; bitfield with the following entries:
  1 - shift key
  2 - ctrl key
  4 - (Mac specific) option key
  8 - Cmd/Alt key
  [all other bits are currently undefined]
  [7] - reserved.
  [8] - host window id.
 
  Keyboard events
  ====================
  Keyboard events are generated when keyboard input is detected.
  [1] - event type 2
  [2] - time stamp
  [3] - character code (Ascii)
  For now the character code is in Mac Roman encoding. See #macToSqueak.
  For key press/release (see [4]), character codes are normalized.
  [4] - press state; integer with the following meaning
  0 - character (aka. key stroke or key still pressed)
  1 - key press (aka. key down)
  2 - key release (aka. key up)
  [5] - modifier keys (same as in mouse events)
  For key press/release (see [4]), modifier keys are still accessible.
  [6] - character code (Unicode UTF32)
  Manual decoding via KeyboardInputInterpreter possible.
  For key press/release (see [4]), character codes are normalized.
  [7] - reserved.
  [8] - host window id.
 
  Mouse-wheel event structure
  ==========================
  Mouse-wheel events are generated when mouse-wheel input is detected.
  [1] - event type 7
  [2] - time stamp
  [3] - horizontal scroll delta
  [4] - vertical scroll delta
  [5] - button state (same as in mouse events)
  [6] - modifier keys (same as in mouse events)
  [7] - reserved.
  [8] - host window id.
  !

Item was changed:
  ----- Method: EventSensor>>createMouseEvent (in category 'mouse') -----
  createMouseEvent
  "create and return a new mouse event from the current mouse
  position; this is useful for restarting normal event queue
  processing after manual polling"
 
  | buttons modifiers pos mapped eventBuffer |
  eventBuffer := Array new: 8.
  buttons := self peekButtons.
  pos := self peekPosition.
  modifiers := buttons bitShift: -3.
  buttons := buttons bitAnd: 7.
  mapped := self mapButtons: buttons modifiers: modifiers.
  eventBuffer
  at: 1
  put: EventTypeMouse;
+ at: 2 put: self eventTimeNow;
- at: 2 put: Time eventMillisecondClock;
  at: 3 put: pos x;
  at: 4 put: pos y;
  at: 5 put: mapped;
  at: 6 put: modifiers.
  ^ eventBuffer!

Item was added:
+ ----- Method: EventSensor>>eventTimeNow (in category 'private') -----
+ eventTimeNow
+ "Answer an event timeStamp that is slightly more recent than that of
+ the most recently processed event. Intended for synthesized events to
+ be processed in line with those from the real event queue."
+
+ ^ lastEventTime + 1.
+ !

Item was changed:
  ----- Method: EventSensor>>peekEventSynthesized (in category 'private') -----
  peekEventSynthesized
  "Return a synthesized event. This method is called if an event driven client wants to receive events but the primary user interface is not event-driven (e.g., the receiver does not have an event queue but only updates its state). This can, for instance, happen if a Morphic World is run in an MVC window. To simplify the clients work this method will always return all available keyboard events first, and then (repeatedly) the mouse events. Since mouse events come last, the client can assume that after one mouse event has been received there are no more to come. Note that it is impossible for EventSensor to determine if a mouse event has been issued before so the client must be aware of the possible problem of getting repeatedly the same mouse events. See HandMorph>>processEvents for an example on how to deal with this."
  | kbd array buttons pos modifiers mapped |
  "First check for keyboard"
  array := Array new: 8.
  keyboardBuffer isEmpty ifFalse:
  ["simulate keyboard event"
  array at: 1 put: EventTypeKeyboard. "evt type"
+ array at: 2 put: self eventTimeNow. "time stamp"
- array at: 2 put: Time eventMillisecondClock. "time stamp"
  array at: 3 put: ((kbd := keyboardBuffer peek) bitAnd: 255). "char code"
  array at: 4 put: EventKeyChar. "key press/release"
  array at: 5 put: (kbd bitShift: -8). "modifier keys"
  ^ array].
 
  "Then check for mouse"
  pos := mousePosition.
  buttons := mouseButtons.
  modifiers := buttons bitShift: -3.
  buttons := buttons bitAnd: 7.
  mapped := self mapButtons: buttons modifiers: modifiers.
  array
  at: 1 put: EventTypeMouse;
+ at: 2 put: self eventTimeNow;
- at: 2 put: Time eventMillisecondClock;
  at: 3 put: pos x;
  at: 4 put: pos y;
  at: 5 put: mapped;
  at: 6 put: modifiers.
  ^ array
 
  !

Item was changed:
  ----- Method: EventSensor>>primGetNextEvent: (in category 'private-I/O') -----
  primGetNextEvent: array
  "Store the next OS event available into the provided array.
  Essential. If the VM is not event driven the ST code will fall
  back to the old-style mechanism and use the state based
  primitives instead."
  | kbd buttons modifiers pos mapped |
  <primitive: 94>
  "Simulate the events"
  array at: 1 put: EventTypeNone. "assume no more events"
 
  "First check for keyboard"
  kbd := self oldPrimKbdNext.
  kbd = nil ifFalse:[
  "simulate keyboard event"
  array at: 1 put: EventTypeKeyboard. "evt type"
+ array at: 2 put: self eventTimeNow. "time stamp"
- array at: 2 put: Time eventMillisecondClock. "time stamp"
  array at: 3 put: (kbd bitAnd: 255). "char code"
  array at: 4 put: EventKeyChar. "key press/release"
  array at: 5 put: (kbd bitShift: -8). "modifier keys"
  ^self].
 
  "Then check for mouse"
  buttons := self oldPrimMouseButtons.
  pos := self oldPrimMousePt.
  modifiers := buttons bitShift: -3.
  buttons := buttons bitAnd: 7.
  mapped := self mapButtons: buttons modifiers: modifiers.
  (pos = mousePosition and:[(mapped bitOr: (modifiers bitShift: 3)) = mouseButtons])
  ifTrue:[^self].
  array
  at: 1 put: EventTypeMouse;
+ at: 2 put: self eventTimeNow;
- at: 2 put: Time eventMillisecondClock;
  at: 3 put: pos x;
  at: 4 put: pos y;
  at: 5 put: mapped;
  at: 6 put: modifiers.
  !

Item was changed:
  ----- Method: EventSensor>>processEvent: (in category 'private-I/O') -----
  processEvent: evt
  "Process a single event. This method is run at high priority."
  | type buttons window |
  type := evt at: 1.
+ lastEventTime := evt at: 2.
 
  "Only process main window events, forward others to host window proxies"
  window := evt at: 8.
  (window isNil or: [window isZero]) ifTrue:
  [window := 1.
  evt at: 8 put: window].
  window = 1 ifFalse: [
  ^Smalltalk at: #HostWindowProxy ifPresent: [:w | w processEvent: evt]].
 
  "Tackle mouse events and mouse wheel events first"
  (type = EventTypeMouse or: [type = EventTypeMouseWheel])
  ifTrue: [buttons := (ButtonDecodeTable at: (evt at: 5) + 1).
  evt at: 5 put: (Smalltalk platformName = 'Mac OS'
  ifTrue: [ buttons ]
  ifFalse: [ self mapButtons: buttons modifiers: (evt at: 6) ]).
  self queueEvent: evt.
  type = EventTypeMouseWheel
  ifTrue: [^ self processMouseWheelEvent: evt].
  type = EventTypeMouse
  ifTrue: [^ self processMouseEvent: evt]].
 
  "Store the event in the queue if there's any"
  type = EventTypeKeyboard
  ifTrue: [ "Check if the event is a user interrupt"
  ((evt at: 4) = EventKeyChar
  and: [((evt at: 3)
  bitOr: (((evt at: 5)
  bitAnd: 8)
  bitShift: 8))
  = interruptKey])
  ifTrue: ["interrupt key is meta - not reported as event"
  ^ interruptSemaphore signal].
  "Decode keys for characters (i.e., duplicate or swap, ctrl <-> alt/cmd)."
  (evt at: 4) = EventKeyChar
  ifTrue: [ | unicode ascii |
  "Copy lookup key first in case of key swap."
  unicode := {evt at: 6. evt at: 5}.
  ascii := {evt at: 3. evt at: 5}.
  KeyDecodeTable "Unicode character first"
  at: unicode
  ifPresent: [:a | evt at: 6 put: a first;
  at: 5 put: a second].
  KeyDecodeTable "ASCII character second"
  at: ascii
  ifPresent: [:a | evt at: 3 put: a first;
  at: 5 put: a second]].
  self queueEvent: evt.
  self processKeyboardEvent: evt .
  ^self ].
 
  "Handle all events other than Keyboard or Mouse."
  self queueEvent: evt.
  !


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-dtl.1340.mcz

Christoph Thiede

Hi David,


how smoothly will this work if the latest send to #processEvent: is some time ago? And couldn't we run into any sort of problems with the "lastEventTime + 1" trick when making multiple fast requests to #eventTimeNow?


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
Gesendet: Mittwoch, 16. September 2020 04:28:39
An: [hidden email]
Betreff: [squeak-dev] The Inbox: Kernel-dtl.1340.mcz
 
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-dtl.1340.mcz

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

Name: Kernel-dtl.1340
Author: dtl
Time: 15 September 2020, 10:28:36.703545 pm
UUID: d155f790-f808-4f68-ae73-3d98434f66d0
Ancestors: Kernel-ul.1339

Implement Sensor eventTimeNow for support of synthesized events. Eliminates the sometimes incorrect assumption that event time stamps must match the obsolete VM millisecond clock, and allows the Windows VM to consistently use native Windows event time stamps in the event queue.

=============== Diff against Kernel-ul.1339 ===============

Item was changed:
  Object subclass: #EventSensor
+        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
-        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore'
         classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodeTable'
         poolDictionaries: 'EventSensorConstants'
         category: 'Kernel-Processes'!
 
  !EventSensor commentStamp: 'mt 12/13/2019 14:38' prior: 0!
  An EventSensor is an interface to the user input devices.
  There is at least one instance of EventSensor named Sensor in the system.
 
  EventSensor is a replacement for the earlier InputSensor implementation based on a set of (optional) event primitives. An EventSensor updates its state when events are received so that all state based users of Sensor (e.g., Sensor keyboard, Sensor leftShiftDown, Sensor mouseButtons) will work exactly as before, by moving the current VM mechanisms into EventSensor itself. An optional input semaphore is part of the new design.
 
  For platforms that support true asynchronous event notification, the semaphore will be signaled to indicate pending events.
  On platforms that do not support asynchronous notifications about events, the UI will have to poll EventSensor periodically to read events from the VM.
 
  Instance variables:
         mouseButtons <Integer>  - mouse button state as replacement for primMouseButtons
         mousePosition <Point>   - mouse position as replacement for primMousePt
         keyboardBuffer <SharedQueue>    - keyboard input buffer
         interruptKey <Integer>                  - currently defined interrupt key
         interruptSemaphore <Semaphore>  - the semaphore signaled when the interruptKey is detected
         eventQueue <SharedQueue>        - an optional event queue for event driven applications
         inputSemaphore <Semaphore>- the semaphore signaled by the VM if asynchronous event notification is supported
         lastEventPoll <Integer>         - the last millisecondClockValue at which we called fetchMoreEvents
         hasInputSemaphore <Boolean>     - true if my inputSemaphore has actually been signaled at least once.
 
  Class variables:
         ButtonDecodeTable <ByteArray> - maps mouse buttons as reported by the VM to ones reported in the events.
         KeyDecodeTable <Dictionary<SmallInteger->SmallInteger>> - maps some keys and their modifiers to other keys (used for instance to map Ctrl-X to Alt-X)
         InterruptSemaphore <Semaphore> - signalled by the the VM and/or the event loop upon receiving an interrupt keystroke.
         InterruptWatcherProcess <Process> - waits on the InterruptSemaphore and then responds as appropriate.
         EventPollPeriod <Integer>       - the number of milliseconds to wait between polling for more events in the userInterruptHandler.
         EventTicklerProcess <Process>   - the process that makes sure that events are polled for often enough (at least every EventPollPeriod milliseconds).
 
  Event format:
  The current event format is very simple. Each event is recorded into an 8 element array. All events must provide some SmallInteger ID (the first field in the event buffer) and a time stamp (the second field in the event buffer), so that the difference between the time stamp of an event and the current time can be reported.
 
  Currently, the following events are defined:
 
  Null event
  =============
  The Null event is returned when the ST side asks for more events but no more events are available.
  Structure:
  [1]           - event type 0
  [2-8] - unused
 
  Mouse event structure
  ==========================
  Mouse events are generated when mouse input is detected.
  [1]   - event type 1
  [2]   - time stamp
  [3]   - mouse x position
  [4]   - mouse y position
  [5]   - button state; bitfield with the following entries:
                 1       -       2r001   yellow (e.g., right) button
                 2       -       2r010   blue (e.g., middle) button
                 4       -       2r100   red (e.g., left) button
                 [all other bits are currently undefined]
  [6]   - modifier keys; bitfield with the following entries:
                 1       -       shift key
                 2       -       ctrl key
                 4       -       (Mac specific) option key
                 8       -       Cmd/Alt key
                 [all other bits are currently undefined]
  [7]   - reserved.
  [8]   - host window id.
 
  Keyboard events
  ====================
  Keyboard events are generated when keyboard input is detected.
  [1]   - event type 2
  [2]   - time stamp
  [3]   - character code (Ascii)
                 For now the character code is in Mac Roman encoding. See #macToSqueak.
                 For key press/release (see [4]), character codes are normalized.
  [4]   - press state; integer with the following meaning
                 0       -       character (aka. key stroke or key still pressed)
                 1       -       key press (aka. key down)
                 2       -        key release (aka. key up)
  [5]   - modifier keys (same as in mouse events)
                 For key press/release (see [4]), modifier keys are still accessible.
  [6]   - character code (Unicode UTF32)
                 Manual decoding via KeyboardInputInterpreter possible.
                 For key press/release (see [4]), character codes are normalized.
  [7]   - reserved.
  [8]   - host window id.
        
  Mouse-wheel event structure
  ==========================
  Mouse-wheel events are generated when mouse-wheel input is detected.
  [1] - event type 7
  [2] - time stamp
  [3] - horizontal scroll delta
  [4] - vertical scroll delta
  [5] - button state (same as in mouse events)
  [6] - modifier keys (same as in mouse events)
  [7] - reserved.
  [8] - host window id.
  !

Item was changed:
  ----- Method: EventSensor>>createMouseEvent (in category 'mouse') -----
  createMouseEvent
         "create and return a new mouse event from the current mouse
         position; this is useful for restarting normal event queue
         processing after manual polling"
 
         | buttons modifiers pos mapped eventBuffer |
         eventBuffer := Array new: 8.
         buttons := self peekButtons.
         pos := self peekPosition.
         modifiers := buttons bitShift: -3.
         buttons := buttons bitAnd: 7.
         mapped := self mapButtons: buttons modifiers: modifiers.
         eventBuffer
                 at: 1
                 put: EventTypeMouse;
+                 at: 2 put: self eventTimeNow;
-                 at: 2 put: Time eventMillisecondClock;
                  at: 3 put: pos x;
                  at: 4 put: pos y;
                  at: 5 put: mapped;
                  at: 6 put: modifiers.
         ^ eventBuffer!

Item was added:
+ ----- Method: EventSensor>>eventTimeNow (in category 'private') -----
+ eventTimeNow
+        "Answer an event timeStamp that is slightly more recent than that of
+        the most recently processed event. Intended for synthesized events to
+        be processed in line with those from the real event queue."
+
+        ^ lastEventTime + 1.
+ !

Item was changed:
  ----- Method: EventSensor>>peekEventSynthesized (in category 'private') -----
  peekEventSynthesized
         "Return a synthesized event. This method is called if an event driven client wants to receive events but the primary user interface is not event-driven (e.g., the receiver does not have an event queue but only updates its state). This can, for instance, happen if a Morphic World is run in an MVC window. To simplify the clients work this method will always return all available keyboard events first, and then (repeatedly) the mouse events. Since mouse events come last, the client can assume that after one mouse event has been received there are no more to come. Note that it is impossible for EventSensor to determine if a mouse event has been issued before so the client must be aware of the possible problem of getting repeatedly the same mouse events. See HandMorph>>processEvents for an example on how to deal with this."
         | kbd array buttons pos modifiers mapped |
         "First check for keyboard"
         array := Array new: 8.
         keyboardBuffer isEmpty ifFalse:
                 ["simulate keyboard event"
                 array at: 1 put: EventTypeKeyboard. "evt type"
+                array at: 2 put: self eventTimeNow. "time stamp"
-                array at: 2 put: Time eventMillisecondClock. "time stamp"
                 array at: 3 put: ((kbd := keyboardBuffer peek) bitAnd: 255). "char code"
                 array at: 4 put: EventKeyChar. "key press/release"
                 array at: 5 put: (kbd bitShift: -8). "modifier keys"
                 ^ array].
 
         "Then check for mouse"
         pos := mousePosition.
         buttons := mouseButtons.
         modifiers := buttons bitShift: -3.
         buttons := buttons bitAnd: 7.
         mapped := self mapButtons: buttons modifiers: modifiers.
         array
                 at: 1 put: EventTypeMouse;
+                at: 2 put: self eventTimeNow;
-                at: 2 put: Time eventMillisecondClock;
                 at: 3 put: pos x;
                 at: 4 put: pos y;
                 at: 5 put: mapped;
                 at: 6 put: modifiers.
         ^ array
 
  !

Item was changed:
  ----- Method: EventSensor>>primGetNextEvent: (in category 'private-I/O') -----
  primGetNextEvent: array
         "Store the next OS event available into the provided array.
         Essential. If the VM is not event driven the ST code will fall
         back to the old-style mechanism and use the state based
         primitives instead."
         | kbd buttons modifiers pos mapped |
         <primitive: 94>
         "Simulate the events"
         array at: 1 put: EventTypeNone. "assume no more events"
 
         "First check for keyboard"
         kbd := self oldPrimKbdNext.
         kbd = nil ifFalse:[
                 "simulate keyboard event"
                 array at: 1 put: EventTypeKeyboard. "evt type"
+                array at: 2 put: self eventTimeNow. "time stamp"
-                array at: 2 put: Time eventMillisecondClock. "time stamp"
                 array at: 3 put: (kbd bitAnd: 255). "char code"
                 array at: 4 put: EventKeyChar. "key press/release"
                 array at: 5 put: (kbd bitShift: -8). "modifier keys"
                 ^self].
 
         "Then check for mouse"
         buttons := self oldPrimMouseButtons.
         pos := self oldPrimMousePt.
         modifiers := buttons bitShift: -3.
         buttons := buttons bitAnd: 7.
         mapped := self mapButtons: buttons modifiers: modifiers.
         (pos = mousePosition and:[(mapped bitOr: (modifiers bitShift: 3)) = mouseButtons])
                 ifTrue:[^self].
         array
                 at: 1 put: EventTypeMouse;
+                at: 2 put: self eventTimeNow;
-                at: 2 put: Time eventMillisecondClock;
                 at: 3 put: pos x;
                 at: 4 put: pos y;
                 at: 5 put: mapped;
                 at: 6 put: modifiers.
  !

Item was changed:
  ----- Method: EventSensor>>processEvent: (in category 'private-I/O') -----
  processEvent: evt
         "Process a single event. This method is run at high priority."
         | type buttons window |
         type := evt at: 1.
+        lastEventTime := evt at: 2.
 
         "Only process main window events, forward others to host window proxies"
         window := evt at: 8.
         (window isNil or: [window isZero]) ifTrue:
                 [window := 1.
                 evt at: 8 put: window].
         window = 1 ifFalse: [
                 ^Smalltalk at: #HostWindowProxy ifPresent: [:w | w processEvent: evt]].
 
         "Tackle mouse events and mouse wheel events first"
         (type = EventTypeMouse or: [type = EventTypeMouseWheel])
                 ifTrue: [buttons := (ButtonDecodeTable at: (evt at: 5) + 1).
                                 evt at: 5 put: (Smalltalk platformName = 'Mac OS'
                                                         ifTrue: [ buttons ]
                                                         ifFalse: [ self mapButtons: buttons modifiers: (evt at: 6) ]).
                                 self queueEvent: evt.
                                 type = EventTypeMouseWheel
                                         ifTrue: [^ self processMouseWheelEvent: evt].                          
                                 type = EventTypeMouse
                                         ifTrue: [^ self processMouseEvent: evt]].
        
         "Store the event in the queue if there's any"
         type = EventTypeKeyboard
                 ifTrue: [ "Check if the event is a user interrupt"
                         ((evt at: 4) = EventKeyChar
                                 and: [((evt at: 3)
                                                 bitOr: (((evt at: 5)
                                                         bitAnd: 8)
                                                         bitShift: 8))
                                                         = interruptKey])
                                         ifTrue: ["interrupt key is meta - not reported as event"
                                                         ^ interruptSemaphore signal].
                         "Decode keys for characters (i.e., duplicate or swap, ctrl <-> alt/cmd)."
                         (evt at: 4) = EventKeyChar
                                 ifTrue: [ | unicode ascii |
                                         "Copy lookup key first in case of key swap."
                                         unicode := {evt at: 6. evt at: 5}.
                                         ascii := {evt at: 3. evt at: 5}.
                                         KeyDecodeTable "Unicode character first"
                                                 at: unicode
                                                 ifPresent: [:a | evt at: 6 put: a first;
                                                                  at: 5 put: a second].
                                         KeyDecodeTable "ASCII character second"
                                                 at: ascii
                                                 ifPresent: [:a | evt at: 3 put: a first;
                                                                  at: 5 put: a second]].
                         self queueEvent: evt.
                         self processKeyboardEvent: evt .
                         ^self ].
                                
         "Handle all events other than Keyboard or Mouse."
         self queueEvent: evt.
         !




Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-dtl.1340.mcz

David T. Lewis
Hi Christoph,

It seems to work just fine :-)

Try putting a halt in that new eventTimeNow method. It is very rarely
called, and the exact value of the timeStamp does not matter just as
long as it is plausibly in sequence with other event time stamps.

Dave



On Wed, Sep 16, 2020 at 11:53:50AM +0000, Thiede, Christoph wrote:

> Hi David,
>
>
> how smoothly will this work if the latest send to #processEvent: is some time ago? And couldn't we run into any sort of problems with the "lastEventTime + 1" trick when making multiple fast requests to #eventTimeNow?
>
>
> Best,
>
> Christoph
>
> <http://www.hpi.de/>
> ________________________________
> Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
> Gesendet: Mittwoch, 16. September 2020 04:28:39
> An: [hidden email]
> Betreff: [squeak-dev] The Inbox: Kernel-dtl.1340.mcz
>
> A new version of Kernel was added to project The Inbox:
> http://source.squeak.org/inbox/Kernel-dtl.1340.mcz
>
> ==================== Summary ====================
>
> Name: Kernel-dtl.1340
> Author: dtl
> Time: 15 September 2020, 10:28:36.703545 pm
> UUID: d155f790-f808-4f68-ae73-3d98434f66d0
> Ancestors: Kernel-ul.1339
>
> Implement Sensor eventTimeNow for support of synthesized events. Eliminates the sometimes incorrect assumption that event time stamps must match the obsolete VM millisecond clock, and allows the Windows VM to consistently use native Windows event time stamps in the event queue.
>
> =============== Diff against Kernel-ul.1339 ===============
>
> Item was changed:
>   Object subclass: #EventSensor
> +        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
> -        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore'
>          classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodeTable'
>          poolDictionaries: 'EventSensorConstants'
>          category: 'Kernel-Processes'!
>
>   !EventSensor commentStamp: 'mt 12/13/2019 14:38' prior: 0!
>   An EventSensor is an interface to the user input devices.
>   There is at least one instance of EventSensor named Sensor in the system.
>
>   EventSensor is a replacement for the earlier InputSensor implementation based on a set of (optional) event primitives. An EventSensor updates its state when events are received so that all state based users of Sensor (e.g., Sensor keyboard, Sensor leftShiftDown, Sensor mouseButtons) will work exactly as before, by moving the current VM mechanisms into EventSensor itself. An optional input semaphore is part of the new design.
>
>   For platforms that support true asynchronous event notification, the semaphore will be signaled to indicate pending events.
>   On platforms that do not support asynchronous notifications about events, the UI will have to poll EventSensor periodically to read events from the VM.
>
>   Instance variables:
>          mouseButtons <Integer>  - mouse button state as replacement for primMouseButtons
>          mousePosition <Point>   - mouse position as replacement for primMousePt
>          keyboardBuffer <SharedQueue>    - keyboard input buffer
>          interruptKey <Integer>                  - currently defined interrupt key
>          interruptSemaphore <Semaphore>  - the semaphore signaled when the interruptKey is detected
>          eventQueue <SharedQueue>        - an optional event queue for event driven applications
>          inputSemaphore <Semaphore>- the semaphore signaled by the VM if asynchronous event notification is supported
>          lastEventPoll <Integer>         - the last millisecondClockValue at which we called fetchMoreEvents
>          hasInputSemaphore <Boolean>     - true if my inputSemaphore has actually been signaled at least once.
>
>   Class variables:
>          ButtonDecodeTable <ByteArray> - maps mouse buttons as reported by the VM to ones reported in the events.
>          KeyDecodeTable <Dictionary<SmallInteger->SmallInteger>> - maps some keys and their modifiers to other keys (used for instance to map Ctrl-X to Alt-X)
>          InterruptSemaphore <Semaphore> - signalled by the the VM and/or the event loop upon receiving an interrupt keystroke.
>          InterruptWatcherProcess <Process> - waits on the InterruptSemaphore and then responds as appropriate.
>          EventPollPeriod <Integer>       - the number of milliseconds to wait between polling for more events in the userInterruptHandler.
>          EventTicklerProcess <Process>   - the process that makes sure that events are polled for often enough (at least every EventPollPeriod milliseconds).
>
>   Event format:
>   The current event format is very simple. Each event is recorded into an 8 element array. All events must provide some SmallInteger ID (the first field in the event buffer) and a time stamp (the second field in the event buffer), so that the difference between the time stamp of an event and the current time can be reported.
>
>   Currently, the following events are defined:
>
>   Null event
>   =============
>   The Null event is returned when the ST side asks for more events but no more events are available.
>   Structure:
>   [1]           - event type 0
>   [2-8] - unused
>
>   Mouse event structure
>   ==========================
>   Mouse events are generated when mouse input is detected.
>   [1]   - event type 1
>   [2]   - time stamp
>   [3]   - mouse x position
>   [4]   - mouse y position
>   [5]   - button state; bitfield with the following entries:
>                  1       -       2r001   yellow (e.g., right) button
>                  2       -       2r010   blue (e.g., middle) button
>                  4       -       2r100   red (e.g., left) button
>                  [all other bits are currently undefined]
>   [6]   - modifier keys; bitfield with the following entries:
>                  1       -       shift key
>                  2       -       ctrl key
>                  4       -       (Mac specific) option key
>                  8       -       Cmd/Alt key
>                  [all other bits are currently undefined]
>   [7]   - reserved.
>   [8]   - host window id.
>
>   Keyboard events
>   ====================
>   Keyboard events are generated when keyboard input is detected.
>   [1]   - event type 2
>   [2]   - time stamp
>   [3]   - character code (Ascii)
>                  For now the character code is in Mac Roman encoding. See #macToSqueak.
>                  For key press/release (see [4]), character codes are normalized.
>   [4]   - press state; integer with the following meaning
>                  0       -       character (aka. key stroke or key still pressed)
>                  1       -       key press (aka. key down)
>                  2       -        key release (aka. key up)
>   [5]   - modifier keys (same as in mouse events)
>                  For key press/release (see [4]), modifier keys are still accessible.
>   [6]   - character code (Unicode UTF32)
>                  Manual decoding via KeyboardInputInterpreter possible.
>                  For key press/release (see [4]), character codes are normalized.
>   [7]   - reserved.
>   [8]   - host window id.
>
>   Mouse-wheel event structure
>   ==========================
>   Mouse-wheel events are generated when mouse-wheel input is detected.
>   [1] - event type 7
>   [2] - time stamp
>   [3] - horizontal scroll delta
>   [4] - vertical scroll delta
>   [5] - button state (same as in mouse events)
>   [6] - modifier keys (same as in mouse events)
>   [7] - reserved.
>   [8] - host window id.
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>createMouseEvent (in category 'mouse') -----
>   createMouseEvent
>          "create and return a new mouse event from the current mouse
>          position; this is useful for restarting normal event queue
>          processing after manual polling"
>
>          | buttons modifiers pos mapped eventBuffer |
>          eventBuffer := Array new: 8.
>          buttons := self peekButtons.
>          pos := self peekPosition.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          eventBuffer
>                  at: 1
>                  put: EventTypeMouse;
> +                 at: 2 put: self eventTimeNow;
> -                 at: 2 put: Time eventMillisecondClock;
>                   at: 3 put: pos x;
>                   at: 4 put: pos y;
>                   at: 5 put: mapped;
>                   at: 6 put: modifiers.
>          ^ eventBuffer!
>
> Item was added:
> + ----- Method: EventSensor>>eventTimeNow (in category 'private') -----
> + eventTimeNow
> +        "Answer an event timeStamp that is slightly more recent than that of
> +        the most recently processed event. Intended for synthesized events to
> +        be processed in line with those from the real event queue."
> +
> +        ^ lastEventTime + 1.
> + !
>
> Item was changed:
>   ----- Method: EventSensor>>peekEventSynthesized (in category 'private') -----
>   peekEventSynthesized
>          "Return a synthesized event. This method is called if an event driven client wants to receive events but the primary user interface is not event-driven (e.g., the receiver does not have an event queue but only updates its state). This can, for instance, happen if a Morphic World is run in an MVC window. To simplify the clients work this method will always return all available keyboard events first, and then (repeatedly) the mouse events. Since mouse events come last, the client can assume that after one mouse event has been received there are no more to come. Note that it is impossible for EventSensor to determine if a mouse event has been issued before so the client must be aware of the possible problem of getting repeatedly the same mouse events. See HandMorph>>processEvents for an example on how to deal with this."
>          | kbd array buttons pos modifiers mapped |
>          "First check for keyboard"
>          array := Array new: 8.
>          keyboardBuffer isEmpty ifFalse:
>                  ["simulate keyboard event"
>                  array at: 1 put: EventTypeKeyboard. "evt type"
> +                array at: 2 put: self eventTimeNow. "time stamp"
> -                array at: 2 put: Time eventMillisecondClock. "time stamp"
>                  array at: 3 put: ((kbd := keyboardBuffer peek) bitAnd: 255). "char code"
>                  array at: 4 put: EventKeyChar. "key press/release"
>                  array at: 5 put: (kbd bitShift: -8). "modifier keys"
>                  ^ array].
>
>          "Then check for mouse"
>          pos := mousePosition.
>          buttons := mouseButtons.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          array
>                  at: 1 put: EventTypeMouse;
> +                at: 2 put: self eventTimeNow;
> -                at: 2 put: Time eventMillisecondClock;
>                  at: 3 put: pos x;
>                  at: 4 put: pos y;
>                  at: 5 put: mapped;
>                  at: 6 put: modifiers.
>          ^ array
>
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>primGetNextEvent: (in category 'private-I/O') -----
>   primGetNextEvent: array
>          "Store the next OS event available into the provided array.
>          Essential. If the VM is not event driven the ST code will fall
>          back to the old-style mechanism and use the state based
>          primitives instead."
>          | kbd buttons modifiers pos mapped |
>          <primitive: 94>
>          "Simulate the events"
>          array at: 1 put: EventTypeNone. "assume no more events"
>
>          "First check for keyboard"
>          kbd := self oldPrimKbdNext.
>          kbd = nil ifFalse:[
>                  "simulate keyboard event"
>                  array at: 1 put: EventTypeKeyboard. "evt type"
> +                array at: 2 put: self eventTimeNow. "time stamp"
> -                array at: 2 put: Time eventMillisecondClock. "time stamp"
>                  array at: 3 put: (kbd bitAnd: 255). "char code"
>                  array at: 4 put: EventKeyChar. "key press/release"
>                  array at: 5 put: (kbd bitShift: -8). "modifier keys"
>                  ^self].
>
>          "Then check for mouse"
>          buttons := self oldPrimMouseButtons.
>          pos := self oldPrimMousePt.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          (pos = mousePosition and:[(mapped bitOr: (modifiers bitShift: 3)) = mouseButtons])
>                  ifTrue:[^self].
>          array
>                  at: 1 put: EventTypeMouse;
> +                at: 2 put: self eventTimeNow;
> -                at: 2 put: Time eventMillisecondClock;
>                  at: 3 put: pos x;
>                  at: 4 put: pos y;
>                  at: 5 put: mapped;
>                  at: 6 put: modifiers.
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>processEvent: (in category 'private-I/O') -----
>   processEvent: evt
>          "Process a single event. This method is run at high priority."
>          | type buttons window |
>          type := evt at: 1.
> +        lastEventTime := evt at: 2.
>
>          "Only process main window events, forward others to host window proxies"
>          window := evt at: 8.
>          (window isNil or: [window isZero]) ifTrue:
>                  [window := 1.
>                  evt at: 8 put: window].
>          window = 1 ifFalse: [
>                  ^Smalltalk at: #HostWindowProxy ifPresent: [:w | w processEvent: evt]].
>
>          "Tackle mouse events and mouse wheel events first"
>          (type = EventTypeMouse or: [type = EventTypeMouseWheel])
>                  ifTrue: [buttons := (ButtonDecodeTable at: (evt at: 5) + 1).
>                                  evt at: 5 put: (Smalltalk platformName = 'Mac OS'
>                                                          ifTrue: [ buttons ]
>                                                          ifFalse: [ self mapButtons: buttons modifiers: (evt at: 6) ]).
>                                  self queueEvent: evt.
>                                  type = EventTypeMouseWheel
>                                          ifTrue: [^ self processMouseWheelEvent: evt].
>                                  type = EventTypeMouse
>                                          ifTrue: [^ self processMouseEvent: evt]].
>
>          "Store the event in the queue if there's any"
>          type = EventTypeKeyboard
>                  ifTrue: [ "Check if the event is a user interrupt"
>                          ((evt at: 4) = EventKeyChar
>                                  and: [((evt at: 3)
>                                                  bitOr: (((evt at: 5)
>                                                          bitAnd: 8)
>                                                          bitShift: 8))
>                                                          = interruptKey])
>                                          ifTrue: ["interrupt key is meta - not reported as event"
>                                                          ^ interruptSemaphore signal].
>                          "Decode keys for characters (i.e., duplicate or swap, ctrl <-> alt/cmd)."
>                          (evt at: 4) = EventKeyChar
>                                  ifTrue: [ | unicode ascii |
>                                          "Copy lookup key first in case of key swap."
>                                          unicode := {evt at: 6. evt at: 5}.
>                                          ascii := {evt at: 3. evt at: 5}.
>                                          KeyDecodeTable "Unicode character first"
>                                                  at: unicode
>                                                  ifPresent: [:a | evt at: 6 put: a first;
>                                                                   at: 5 put: a second].
>                                          KeyDecodeTable "ASCII character second"
>                                                  at: ascii
>                                                  ifPresent: [:a | evt at: 3 put: a first;
>                                                                   at: 5 put: a second]].
>                          self queueEvent: evt.
>                          self processKeyboardEvent: evt .
>                          ^self ].
>
>          "Handle all events other than Keyboard or Mouse."
>          self queueEvent: evt.
>          !
>
>

>


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-dtl.1340.mcz

Christoph Thiede

Alright, then it seems fine!


PS: Did you know #isThisEverCalled? That's a bit cooler than "putting a halt somewhere". ;-)


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von David T. Lewis <[hidden email]>
Gesendet: Mittwoch, 16. September 2020 14:13:03
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] The Inbox: Kernel-dtl.1340.mcz
 
Hi Christoph,

It seems to work just fine :-)

Try putting a halt in that new eventTimeNow method. It is very rarely
called, and the exact value of the timeStamp does not matter just as
long as it is plausibly in sequence with other event time stamps.

Dave



On Wed, Sep 16, 2020 at 11:53:50AM +0000, Thiede, Christoph wrote:
> Hi David,
>
>
> how smoothly will this work if the latest send to #processEvent: is some time ago? And couldn't we run into any sort of problems with the "lastEventTime + 1" trick when making multiple fast requests to #eventTimeNow?
>
>
> Best,
>
> Christoph
>
> <http://www.hpi.de/>
> ________________________________
> Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
> Gesendet: Mittwoch, 16. September 2020 04:28:39
> An: [hidden email]
> Betreff: [squeak-dev] The Inbox: Kernel-dtl.1340.mcz
>
> A new version of Kernel was added to project The Inbox:
> http://source.squeak.org/inbox/Kernel-dtl.1340.mcz
>
> ==================== Summary ====================
>
> Name: Kernel-dtl.1340
> Author: dtl
> Time: 15 September 2020, 10:28:36.703545 pm
> UUID: d155f790-f808-4f68-ae73-3d98434f66d0
> Ancestors: Kernel-ul.1339
>
> Implement Sensor eventTimeNow for support of synthesized events. Eliminates the sometimes incorrect assumption that event time stamps must match the obsolete VM millisecond clock, and allows the Windows VM to consistently use native Windows event time stamps in the event queue.
>
> =============== Diff against Kernel-ul.1339 ===============
>
> Item was changed:
>   Object subclass: #EventSensor
> +        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
> -        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore'
>          classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodeTable'
>          poolDictionaries: 'EventSensorConstants'
>          category: 'Kernel-Processes'!
>
>   !EventSensor commentStamp: 'mt 12/13/2019 14:38' prior: 0!
>   An EventSensor is an interface to the user input devices.
>   There is at least one instance of EventSensor named Sensor in the system.
>
>   EventSensor is a replacement for the earlier InputSensor implementation based on a set of (optional) event primitives. An EventSensor updates its state when events are received so that all state based users of Sensor (e.g., Sensor keyboard, Sensor leftShiftDown, Sensor mouseButtons) will work exactly as before, by moving the current VM mechanisms into EventSensor itself. An optional input semaphore is part of the new design.
>
>   For platforms that support true asynchronous event notification, the semaphore will be signaled to indicate pending events.
>   On platforms that do not support asynchronous notifications about events, the UI will have to poll EventSensor periodically to read events from the VM.
>
>   Instance variables:
>          mouseButtons <Integer>  - mouse button state as replacement for primMouseButtons
>          mousePosition <Point>   - mouse position as replacement for primMousePt
>          keyboardBuffer <SharedQueue>    - keyboard input buffer
>          interruptKey <Integer>                  - currently defined interrupt key
>          interruptSemaphore <Semaphore>  - the semaphore signaled when the interruptKey is detected
>          eventQueue <SharedQueue>        - an optional event queue for event driven applications
>          inputSemaphore <Semaphore>- the semaphore signaled by the VM if asynchronous event notification is supported
>          lastEventPoll <Integer>         - the last millisecondClockValue at which we called fetchMoreEvents
>          hasInputSemaphore <Boolean>     - true if my inputSemaphore has actually been signaled at least once.
>
>   Class variables:
>          ButtonDecodeTable <ByteArray> - maps mouse buttons as reported by the VM to ones reported in the events.
>          KeyDecodeTable <Dictionary<SmallInteger->SmallInteger>> - maps some keys and their modifiers to other keys (used for instance to map Ctrl-X to Alt-X)
>          InterruptSemaphore <Semaphore> - signalled by the the VM and/or the event loop upon receiving an interrupt keystroke.
>          InterruptWatcherProcess <Process> - waits on the InterruptSemaphore and then responds as appropriate.
>          EventPollPeriod <Integer>       - the number of milliseconds to wait between polling for more events in the userInterruptHandler.
>          EventTicklerProcess <Process>   - the process that makes sure that events are polled for often enough (at least every EventPollPeriod milliseconds).
>
>   Event format:
>   The current event format is very simple. Each event is recorded into an 8 element array. All events must provide some SmallInteger ID (the first field in the event buffer) and a time stamp (the second field in the event buffer), so that the difference between the time stamp of an event and the current time can be reported.
>
>   Currently, the following events are defined:
>
>   Null event
>   =============
>   The Null event is returned when the ST side asks for more events but no more events are available.
>   Structure:
>   [1]           - event type 0
>   [2-8] - unused
>
>   Mouse event structure
>   ==========================
>   Mouse events are generated when mouse input is detected.
>   [1]   - event type 1
>   [2]   - time stamp
>   [3]   - mouse x position
>   [4]   - mouse y position
>   [5]   - button state; bitfield with the following entries:
>                  1       -       2r001   yellow (e.g., right) button
>                  2       -       2r010   blue (e.g., middle) button
>                  4       -       2r100   red (e.g., left) button
>                  [all other bits are currently undefined]
>   [6]   - modifier keys; bitfield with the following entries:
>                  1       -       shift key
>                  2       -       ctrl key
>                  4       -       (Mac specific) option key
>                  8       -       Cmd/Alt key
>                  [all other bits are currently undefined]
>   [7]   - reserved.
>   [8]   - host window id.
>
>   Keyboard events
>   ====================
>   Keyboard events are generated when keyboard input is detected.
>   [1]   - event type 2
>   [2]   - time stamp
>   [3]   - character code (Ascii)
>                  For now the character code is in Mac Roman encoding. See #macToSqueak.
>                  For key press/release (see [4]), character codes are normalized.
>   [4]   - press state; integer with the following meaning
>                  0       -       character (aka. key stroke or key still pressed)
>                  1       -       key press (aka. key down)
>                  2       -        key release (aka. key up)
>   [5]   - modifier keys (same as in mouse events)
>                  For key press/release (see [4]), modifier keys are still accessible.
>   [6]   - character code (Unicode UTF32)
>                  Manual decoding via KeyboardInputInterpreter possible.
>                  For key press/release (see [4]), character codes are normalized.
>   [7]   - reserved.
>   [8]   - host window id.
>
>   Mouse-wheel event structure
>   ==========================
>   Mouse-wheel events are generated when mouse-wheel input is detected.
>   [1] - event type 7
>   [2] - time stamp
>   [3] - horizontal scroll delta
>   [4] - vertical scroll delta
>   [5] - button state (same as in mouse events)
>   [6] - modifier keys (same as in mouse events)
>   [7] - reserved.
>   [8] - host window id.
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>createMouseEvent (in category 'mouse') -----
>   createMouseEvent
>          "create and return a new mouse event from the current mouse
>          position; this is useful for restarting normal event queue
>          processing after manual polling"
>
>          | buttons modifiers pos mapped eventBuffer |
>          eventBuffer := Array new: 8.
>          buttons := self peekButtons.
>          pos := self peekPosition.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          eventBuffer
>                  at: 1
>                  put: EventTypeMouse;
> +                 at: 2 put: self eventTimeNow;
> -                 at: 2 put: Time eventMillisecondClock;
>                   at: 3 put: pos x;
>                   at: 4 put: pos y;
>                   at: 5 put: mapped;
>                   at: 6 put: modifiers.
>          ^ eventBuffer!
>
> Item was added:
> + ----- Method: EventSensor>>eventTimeNow (in category 'private') -----
> + eventTimeNow
> +        "Answer an event timeStamp that is slightly more recent than that of
> +        the most recently processed event. Intended for synthesized events to
> +        be processed in line with those from the real event queue."
> +
> +        ^ lastEventTime + 1.
> + !
>
> Item was changed:
>   ----- Method: EventSensor>>peekEventSynthesized (in category 'private') -----
>   peekEventSynthesized
>          "Return a synthesized event. This method is called if an event driven client wants to receive events but the primary user interface is not event-driven (e.g., the receiver does not have an event queue but only updates its state). This can, for instance, happen if a Morphic World is run in an MVC window. To simplify the clients work this method will always return all available keyboard events first, and then (repeatedly) the mouse events. Since mouse events come last, the client can assume that after one mouse event has been received there are no more to come. Note that it is impossible for EventSensor to determine if a mouse event has been issued before so the client must be aware of the possible problem of getting repeatedly the same mouse events. See HandMorph>>processEvents for an example on how to deal with this."
>          | kbd array buttons pos modifiers mapped |
>          "First check for keyboard"
>          array := Array new: 8.
>          keyboardBuffer isEmpty ifFalse:
>                  ["simulate keyboard event"
>                  array at: 1 put: EventTypeKeyboard. "evt type"
> +                array at: 2 put: self eventTimeNow. "time stamp"
> -                array at: 2 put: Time eventMillisecondClock. "time stamp"
>                  array at: 3 put: ((kbd := keyboardBuffer peek) bitAnd: 255). "char code"
>                  array at: 4 put: EventKeyChar. "key press/release"
>                  array at: 5 put: (kbd bitShift: -8). "modifier keys"
>                  ^ array].
>
>          "Then check for mouse"
>          pos := mousePosition.
>          buttons := mouseButtons.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          array
>                  at: 1 put: EventTypeMouse;
> +                at: 2 put: self eventTimeNow;
> -                at: 2 put: Time eventMillisecondClock;
>                  at: 3 put: pos x;
>                  at: 4 put: pos y;
>                  at: 5 put: mapped;
>                  at: 6 put: modifiers.
>          ^ array
>
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>primGetNextEvent: (in category 'private-I/O') -----
>   primGetNextEvent: array
>          "Store the next OS event available into the provided array.
>          Essential. If the VM is not event driven the ST code will fall
>          back to the old-style mechanism and use the state based
>          primitives instead."
>          | kbd buttons modifiers pos mapped |
>          <primitive: 94>
>          "Simulate the events"
>          array at: 1 put: EventTypeNone. "assume no more events"
>
>          "First check for keyboard"
>          kbd := self oldPrimKbdNext.
>          kbd = nil ifFalse:[
>                  "simulate keyboard event"
>                  array at: 1 put: EventTypeKeyboard. "evt type"
> +                array at: 2 put: self eventTimeNow. "time stamp"
> -                array at: 2 put: Time eventMillisecondClock. "time stamp"
>                  array at: 3 put: (kbd bitAnd: 255). "char code"
>                  array at: 4 put: EventKeyChar. "key press/release"
>                  array at: 5 put: (kbd bitShift: -8). "modifier keys"
>                  ^self].
>
>          "Then check for mouse"
>          buttons := self oldPrimMouseButtons.
>          pos := self oldPrimMousePt.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          (pos = mousePosition and:[(mapped bitOr: (modifiers bitShift: 3)) = mouseButtons])
>                  ifTrue:[^self].
>          array
>                  at: 1 put: EventTypeMouse;
> +                at: 2 put: self eventTimeNow;
> -                at: 2 put: Time eventMillisecondClock;
>                  at: 3 put: pos x;
>                  at: 4 put: pos y;
>                  at: 5 put: mapped;
>                  at: 6 put: modifiers.
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>processEvent: (in category 'private-I/O') -----
>   processEvent: evt
>          "Process a single event. This method is run at high priority."
>          | type buttons window |
>          type := evt at: 1.
> +        lastEventTime := evt at: 2.
>
>          "Only process main window events, forward others to host window proxies"
>          window := evt at: 8.
>          (window isNil or: [window isZero]) ifTrue:
>                  [window := 1.
>                  evt at: 8 put: window].
>          window = 1 ifFalse: [
>                  ^Smalltalk at: #HostWindowProxy ifPresent: [:w | w processEvent: evt]].
>
>          "Tackle mouse events and mouse wheel events first"
>          (type = EventTypeMouse or: [type = EventTypeMouseWheel])
>                  ifTrue: [buttons := (ButtonDecodeTable at: (evt at: 5) + 1).
>                                  evt at: 5 put: (Smalltalk platformName = 'Mac OS'
>                                                          ifTrue: [ buttons ]
>                                                          ifFalse: [ self mapButtons: buttons modifiers: (evt at: 6) ]).
>                                  self queueEvent: evt.
>                                  type = EventTypeMouseWheel
>                                          ifTrue: [^ self processMouseWheelEvent: evt].
>                                  type = EventTypeMouse
>                                          ifTrue: [^ self processMouseEvent: evt]].
>
>          "Store the event in the queue if there's any"
>          type = EventTypeKeyboard
>                  ifTrue: [ "Check if the event is a user interrupt"
>                          ((evt at: 4) = EventKeyChar
>                                  and: [((evt at: 3)
>                                                  bitOr: (((evt at: 5)
>                                                          bitAnd: 8)
>                                                          bitShift: 8))
>                                                          = interruptKey])
>                                          ifTrue: ["interrupt key is meta - not reported as event"
>                                                          ^ interruptSemaphore signal].
>                          "Decode keys for characters (i.e., duplicate or swap, ctrl <-> alt/cmd)."
>                          (evt at: 4) = EventKeyChar
>                                  ifTrue: [ | unicode ascii |
>                                          "Copy lookup key first in case of key swap."
>                                          unicode := {evt at: 6. evt at: 5}.
>                                          ascii := {evt at: 3. evt at: 5}.
>                                          KeyDecodeTable "Unicode character first"
>                                                  at: unicode
>                                                  ifPresent: [:a | evt at: 6 put: a first;
>                                                                   at: 5 put: a second].
>                                          KeyDecodeTable "ASCII character second"
>                                                  at: ascii
>                                                  ifPresent: [:a | evt at: 3 put: a first;
>                                                                   at: 5 put: a second]].
>                          self queueEvent: evt.
>                          self processKeyboardEvent: evt .
>                          ^self ].
>
>          "Handle all events other than Keyboard or Mouse."
>          self queueEvent: evt.
>          !
>
>

>




Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-dtl.1340.mcz

David T. Lewis
On Wed, Sep 16, 2020 at 02:41:13PM +0000, Thiede, Christoph wrote:
> Alright, then it seems fine!
>
>
> PS: Did you know #isThisEverCalled? That's a bit cooler than "putting a halt somewhere". ;-)
>
>

Actually no, I did not know about that. Thanks for the tip :-)

Amazing it's been in the image since day one and I never noticed.

Dave



Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-dtl.1340.mcz

Eliot Miranda-2
In reply to this post by Christoph Thiede
Hi Christoph,

On Wed, Sep 16, 2020 at 7:41 AM Thiede, Christoph <[hidden email]> wrote:

Alright, then it seems fine!


PS: Did you know #isThisEverCalled? That's a bit cooler than "putting a halt somewhere". ;-)


What would be cooler than the current implementation is something that maintains a pair of dates in the properties of a method that sends isThisEverCalled. If the method's properties are empty then isThisEverCalled would (silently) update the properties with the "start date".  Subsequent calls would set the "end date" to the current time.  We could then browse for senders of isThisEverCalled and see when exectly was the method called.  No propertiers => it wasn't called.  properties with an end date long in the past => not for a while.  The problem with an implementation based on halt is that one can only use it for code that can safely be halted.


Best,

Christoph


Von: Squeak-dev <[hidden email]> im Auftrag von David T. Lewis <[hidden email]>
Gesendet: Mittwoch, 16. September 2020 14:13:03
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] The Inbox: Kernel-dtl.1340.mcz
 
Hi Christoph,

It seems to work just fine :-)

Try putting a halt in that new eventTimeNow method. It is very rarely
called, and the exact value of the timeStamp does not matter just as
long as it is plausibly in sequence with other event time stamps.

Dave



On Wed, Sep 16, 2020 at 11:53:50AM +0000, Thiede, Christoph wrote:
> Hi David,
>
>
> how smoothly will this work if the latest send to #processEvent: is some time ago? And couldn't we run into any sort of problems with the "lastEventTime + 1" trick when making multiple fast requests to #eventTimeNow?
>
>
> Best,
>
> Christoph
>
> <http://www.hpi.de/>
> ________________________________
> Von: Squeak-dev <[hidden email]> im Auftrag von [hidden email] <[hidden email]>
> Gesendet: Mittwoch, 16. September 2020 04:28:39
> An: [hidden email]
> Betreff: [squeak-dev] The Inbox: Kernel-dtl.1340.mcz
>
> A new version of Kernel was added to project The Inbox:
> http://source.squeak.org/inbox/Kernel-dtl.1340.mcz
>
> ==================== Summary ====================
>
> Name: Kernel-dtl.1340
> Author: dtl
> Time: 15 September 2020, 10:28:36.703545 pm
> UUID: d155f790-f808-4f68-ae73-3d98434f66d0
> Ancestors: Kernel-ul.1339
>
> Implement Sensor eventTimeNow for support of synthesized events. Eliminates the sometimes incorrect assumption that event time stamps must match the obsolete VM millisecond clock, and allows the Windows VM to consistently use native Windows event time stamps in the event queue.
>
> =============== Diff against Kernel-ul.1339 ===============
>
> Item was changed:
>   Object subclass: #EventSensor
> +        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
> -        instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore'
>          classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodeTable'
>          poolDictionaries: 'EventSensorConstants'
>          category: 'Kernel-Processes'!
>
>   !EventSensor commentStamp: 'mt 12/13/2019 14:38' prior: 0!
>   An EventSensor is an interface to the user input devices.
>   There is at least one instance of EventSensor named Sensor in the system.
>
>   EventSensor is a replacement for the earlier InputSensor implementation based on a set of (optional) event primitives. An EventSensor updates its state when events are received so that all state based users of Sensor (e.g., Sensor keyboard, Sensor leftShiftDown, Sensor mouseButtons) will work exactly as before, by moving the current VM mechanisms into EventSensor itself. An optional input semaphore is part of the new design.
>
>   For platforms that support true asynchronous event notification, the semaphore will be signaled to indicate pending events.
>   On platforms that do not support asynchronous notifications about events, the UI will have to poll EventSensor periodically to read events from the VM.
>
>   Instance variables:
>          mouseButtons <Integer>  - mouse button state as replacement for primMouseButtons
>          mousePosition <Point>   - mouse position as replacement for primMousePt
>          keyboardBuffer <SharedQueue>    - keyboard input buffer
>          interruptKey <Integer>                  - currently defined interrupt key
>          interruptSemaphore <Semaphore>  - the semaphore signaled when the interruptKey is detected
>          eventQueue <SharedQueue>        - an optional event queue for event driven applications
>          inputSemaphore <Semaphore>- the semaphore signaled by the VM if asynchronous event notification is supported
>          lastEventPoll <Integer>         - the last millisecondClockValue at which we called fetchMoreEvents
>          hasInputSemaphore <Boolean>     - true if my inputSemaphore has actually been signaled at least once.
>
>   Class variables:
>          ButtonDecodeTable <ByteArray> - maps mouse buttons as reported by the VM to ones reported in the events.
>          KeyDecodeTable <Dictionary<SmallInteger->SmallInteger>> - maps some keys and their modifiers to other keys (used for instance to map Ctrl-X to Alt-X)
>          InterruptSemaphore <Semaphore> - signalled by the the VM and/or the event loop upon receiving an interrupt keystroke.
>          InterruptWatcherProcess <Process> - waits on the InterruptSemaphore and then responds as appropriate.
>          EventPollPeriod <Integer>       - the number of milliseconds to wait between polling for more events in the userInterruptHandler.
>          EventTicklerProcess <Process>   - the process that makes sure that events are polled for often enough (at least every EventPollPeriod milliseconds).
>
>   Event format:
>   The current event format is very simple. Each event is recorded into an 8 element array. All events must provide some SmallInteger ID (the first field in the event buffer) and a time stamp (the second field in the event buffer), so that the difference between the time stamp of an event and the current time can be reported.
>
>   Currently, the following events are defined:
>
>   Null event
>   =============
>   The Null event is returned when the ST side asks for more events but no more events are available.
>   Structure:
>   [1]           - event type 0
>   [2-8] - unused
>
>   Mouse event structure
>   ==========================
>   Mouse events are generated when mouse input is detected.
>   [1]   - event type 1
>   [2]   - time stamp
>   [3]   - mouse x position
>   [4]   - mouse y position
>   [5]   - button state; bitfield with the following entries:
>                  1       -       2r001   yellow (e.g., right) button
>                  2       -       2r010   blue (e.g., middle) button
>                  4       -       2r100   red (e.g., left) button
>                  [all other bits are currently undefined]
>   [6]   - modifier keys; bitfield with the following entries:
>                  1       -       shift key
>                  2       -       ctrl key
>                  4       -       (Mac specific) option key
>                  8       -       Cmd/Alt key
>                  [all other bits are currently undefined]
>   [7]   - reserved.
>   [8]   - host window id.
>
>   Keyboard events
>   ====================
>   Keyboard events are generated when keyboard input is detected.
>   [1]   - event type 2
>   [2]   - time stamp
>   [3]   - character code (Ascii)
>                  For now the character code is in Mac Roman encoding. See #macToSqueak.
>                  For key press/release (see [4]), character codes are normalized.
>   [4]   - press state; integer with the following meaning
>                  0       -       character (aka. key stroke or key still pressed)
>                  1       -       key press (aka. key down)
>                  2       -        key release (aka. key up)
>   [5]   - modifier keys (same as in mouse events)
>                  For key press/release (see [4]), modifier keys are still accessible.
>   [6]   - character code (Unicode UTF32)
>                  Manual decoding via KeyboardInputInterpreter possible.
>                  For key press/release (see [4]), character codes are normalized.
>   [7]   - reserved.
>   [8]   - host window id.
>
>   Mouse-wheel event structure
>   ==========================
>   Mouse-wheel events are generated when mouse-wheel input is detected.
>   [1] - event type 7
>   [2] - time stamp
>   [3] - horizontal scroll delta
>   [4] - vertical scroll delta
>   [5] - button state (same as in mouse events)
>   [6] - modifier keys (same as in mouse events)
>   [7] - reserved.
>   [8] - host window id.
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>createMouseEvent (in category 'mouse') -----
>   createMouseEvent
>          "create and return a new mouse event from the current mouse
>          position; this is useful for restarting normal event queue
>          processing after manual polling"
>
>          | buttons modifiers pos mapped eventBuffer |
>          eventBuffer := Array new: 8.
>          buttons := self peekButtons.
>          pos := self peekPosition.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          eventBuffer
>                  at: 1
>                  put: EventTypeMouse;
> +                 at: 2 put: self eventTimeNow;
> -                 at: 2 put: Time eventMillisecondClock;
>                   at: 3 put: pos x;
>                   at: 4 put: pos y;
>                   at: 5 put: mapped;
>                   at: 6 put: modifiers.
>          ^ eventBuffer!
>
> Item was added:
> + ----- Method: EventSensor>>eventTimeNow (in category 'private') -----
> + eventTimeNow
> +        "Answer an event timeStamp that is slightly more recent than that of
> +        the most recently processed event. Intended for synthesized events to
> +        be processed in line with those from the real event queue."
> +
> +        ^ lastEventTime + 1.
> + !
>
> Item was changed:
>   ----- Method: EventSensor>>peekEventSynthesized (in category 'private') -----
>   peekEventSynthesized
>          "Return a synthesized event. This method is called if an event driven client wants to receive events but the primary user interface is not event-driven (e.g., the receiver does not have an event queue but only updates its state). This can, for instance, happen if a Morphic World is run in an MVC window. To simplify the clients work this method will always return all available keyboard events first, and then (repeatedly) the mouse events. Since mouse events come last, the client can assume that after one mouse event has been received there are no more to come. Note that it is impossible for EventSensor to determine if a mouse event has been issued before so the client must be aware of the possible problem of getting repeatedly the same mouse events. See HandMorph>>processEvents for an example on how to deal with this."
>          | kbd array buttons pos modifiers mapped |
>          "First check for keyboard"
>          array := Array new: 8.
>          keyboardBuffer isEmpty ifFalse:
>                  ["simulate keyboard event"
>                  array at: 1 put: EventTypeKeyboard. "evt type"
> +                array at: 2 put: self eventTimeNow. "time stamp"
> -                array at: 2 put: Time eventMillisecondClock. "time stamp"
>                  array at: 3 put: ((kbd := keyboardBuffer peek) bitAnd: 255). "char code"
>                  array at: 4 put: EventKeyChar. "key press/release"
>                  array at: 5 put: (kbd bitShift: -8). "modifier keys"
>                  ^ array].
>
>          "Then check for mouse"
>          pos := mousePosition.
>          buttons := mouseButtons.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          array
>                  at: 1 put: EventTypeMouse;
> +                at: 2 put: self eventTimeNow;
> -                at: 2 put: Time eventMillisecondClock;
>                  at: 3 put: pos x;
>                  at: 4 put: pos y;
>                  at: 5 put: mapped;
>                  at: 6 put: modifiers.
>          ^ array
>
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>primGetNextEvent: (in category 'private-I/O') -----
>   primGetNextEvent: array
>          "Store the next OS event available into the provided array.
>          Essential. If the VM is not event driven the ST code will fall
>          back to the old-style mechanism and use the state based
>          primitives instead."
>          | kbd buttons modifiers pos mapped |
>          <primitive: 94>
>          "Simulate the events"
>          array at: 1 put: EventTypeNone. "assume no more events"
>
>          "First check for keyboard"
>          kbd := self oldPrimKbdNext.
>          kbd = nil ifFalse:[
>                  "simulate keyboard event"
>                  array at: 1 put: EventTypeKeyboard. "evt type"
> +                array at: 2 put: self eventTimeNow. "time stamp"
> -                array at: 2 put: Time eventMillisecondClock. "time stamp"
>                  array at: 3 put: (kbd bitAnd: 255). "char code"
>                  array at: 4 put: EventKeyChar. "key press/release"
>                  array at: 5 put: (kbd bitShift: -8). "modifier keys"
>                  ^self].
>
>          "Then check for mouse"
>          buttons := self oldPrimMouseButtons.
>          pos := self oldPrimMousePt.
>          modifiers := buttons bitShift: -3.
>          buttons := buttons bitAnd: 7.
>          mapped := self mapButtons: buttons modifiers: modifiers.
>          (pos = mousePosition and:[(mapped bitOr: (modifiers bitShift: 3)) = mouseButtons])
>                  ifTrue:[^self].
>          array
>                  at: 1 put: EventTypeMouse;
> +                at: 2 put: self eventTimeNow;
> -                at: 2 put: Time eventMillisecondClock;
>                  at: 3 put: pos x;
>                  at: 4 put: pos y;
>                  at: 5 put: mapped;
>                  at: 6 put: modifiers.
>   !
>
> Item was changed:
>   ----- Method: EventSensor>>processEvent: (in category 'private-I/O') -----
>   processEvent: evt
>          "Process a single event. This method is run at high priority."
>          | type buttons window |
>          type := evt at: 1.
> +        lastEventTime := evt at: 2.
>
>          "Only process main window events, forward others to host window proxies"
>          window := evt at: 8.
>          (window isNil or: [window isZero]) ifTrue:
>                  [window := 1.
>                  evt at: 8 put: window].
>          window = 1 ifFalse: [
>                  ^Smalltalk at: #HostWindowProxy ifPresent: [:w | w processEvent: evt]].
>
>          "Tackle mouse events and mouse wheel events first"
>          (type = EventTypeMouse or: [type = EventTypeMouseWheel])
>                  ifTrue: [buttons := (ButtonDecodeTable at: (evt at: 5) + 1).
>                                  evt at: 5 put: (Smalltalk platformName = 'Mac OS'
>                                                          ifTrue: [ buttons ]
>                                                          ifFalse: [ self mapButtons: buttons modifiers: (evt at: 6) ]).
>                                  self queueEvent: evt.
>                                  type = EventTypeMouseWheel
>                                          ifTrue: [^ self processMouseWheelEvent: evt].
>                                  type = EventTypeMouse
>                                          ifTrue: [^ self processMouseEvent: evt]].
>
>          "Store the event in the queue if there's any"
>          type = EventTypeKeyboard
>                  ifTrue: [ "Check if the event is a user interrupt"
>                          ((evt at: 4) = EventKeyChar
>                                  and: [((evt at: 3)
>                                                  bitOr: (((evt at: 5)
>                                                          bitAnd: 8)
>                                                          bitShift: 8))
>                                                          = interruptKey])
>                                          ifTrue: ["interrupt key is meta - not reported as event"
>                                                          ^ interruptSemaphore signal].
>                          "Decode keys for characters (i.e., duplicate or swap, ctrl <-> alt/cmd)."
>                          (evt at: 4) = EventKeyChar
>                                  ifTrue: [ | unicode ascii |
>                                          "Copy lookup key first in case of key swap."
>                                          unicode := {evt at: 6. evt at: 5}.
>                                          ascii := {evt at: 3. evt at: 5}.
>                                          KeyDecodeTable "Unicode character first"
>                                                  at: unicode
>                                                  ifPresent: [:a | evt at: 6 put: a first;
>                                                                   at: 5 put: a second].
>                                          KeyDecodeTable "ASCII character second"
>                                                  at: ascii
>                                                  ifPresent: [:a | evt at: 3 put: a first;
>                                                                   at: 5 put: a second]].
>                          self queueEvent: evt.
>                          self processKeyboardEvent: evt .
>                          ^self ].
>
>          "Handle all events other than Keyboard or Mouse."
>          self queueEvent: evt.
>          !
>
>

>





--
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-dtl.1340.mcz

timrowledge


> On 2020-09-16, at 8:21 AM, Eliot Miranda <[hidden email]> wrote:
>
> Hi Christoph,
>
> On Wed, Sep 16, 2020 at 7:41 AM Thiede, Christoph <[hidden email]> wrote:
> Alright, then it seems fine!
>
>
>
> PS: Did you know #isThisEverCalled? That's a bit cooler than "putting a halt somewhere". ;-)
>
>
> What would be cooler than the current implementation is something that maintains a pair of dates in the properties of a method that sends isThisEverCalled. If the method's properties are empty then isThisEverCalled would (silently) update the properties with the "start date".  Subsequent calls would set the "end date" to the current time.  We could then browse for senders of isThisEverCalled and see when exectly was the method called.  No propertiers => it wasn't called.  properties with an end date long in the past => not for a while.  The problem with an implementation based on halt is that one can only use it for code that can safely be halted.

Ooh, sneaky. Could also hook to a logger that writes to non-image output (file/stdio/mqtt/etc) to get live updates.


tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Liability: a valuable political skill