The Trunk: Kernel-mt.1403.mcz

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

The Trunk: Kernel-mt.1403.mcz

commits-2
Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-mt.1403.mcz

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

Name: Kernel-mt.1403
Author: mt
Time: 18 June 2021, 8:32:18.330904 am
UUID: 896b2999-9c3e-4df2-985b-92adf7d228a4
Ancestors: Kernel-nice.1402

Next iteration on virtual-key mapping to be consistent across all of our supported platforms. Works fine for Windows and macOS. Works okay-ish on X11 because of (yet) missing scan-codes.

See http://forum.world.st/Please-try-out-Cross-platform-mapping-for-virtual-key-codes-tp5129188.html

=============== Diff against Kernel-nice.1402 ===============

Item was changed:
  Object subclass: #EventSensor
  instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
+ classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodePreferences KeyDecodeTable VirtualKeyTable'
- classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodePreferences 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 class>>initialize (in category 'class initialization') -----
  initialize
 
  Smalltalk addToStartUpList: self before: ProcessorScheduler.
  Smalltalk addToShutDownList: self.
 
  KeyDecodePreferences := Dictionary new.
 
  self installKeyDecodeTable.
+ self installMouseDecodeTable.
+ self installVirtualKeyTable.!
- self installMouseDecodeTable.!

Item was changed:
  ----- Method: EventSensor class>>installMappingToPrintableCharacters (in category 'key decode table') -----
  installMappingToPrintableCharacters
  "Only applies when the CONTROL modifier is present!! Control characters that can directly be triggered -- such as CR, ENTER, BS, DEL, POS1, END -- will not be mapped."
 
  self flag: #windowsOnly. "mt: The CONTROL modifier might directly change the control character. Examples: CTRL+CR(13) arrives as CTRL+LF(10), CTRL+BS(8) arrives as CTRL+DEL(127). If you have no other means to input LF(10) or DEL(127), you might have to disable this mapping to printable characters."
 
+ 1 "SOH" to: 27 "ESC" do: [:control |
+ #(2r0010 "ctrl" 2r0110 "ctrl+opt" 2r1010 "ctrl+cmd" 2r1110 "ctrl+opt+cmd")
+ do: [:modifiers | "Note that only macOS needs those other combinations."
+ KeyDecodeTable
+ at: { control . modifiers }
+ put: { control bitOr: 16r60 "+96" . modifiers }].
+ #(2r0011 "shift+ctrl" 2r0111 "shift+ctrl+opt" 2r1011 "shift+ctrl+cmd" 2r1111 "shift+ctrl+opt+cmd")
+ do: [:modifiers | "Note that only macOS needs those other combinations."
+ KeyDecodeTable
+ at: { control . modifiers }
+ put: { control bitOr: 16r40 "+64" . modifiers }]].
+
+ self flag: #macOSOnly. "mt: Ctrl+Space arrives as NUL character, which would be mapped to $@ with the above rules. So, ensure that Ctrl+Space works across platforms."
+ KeyDecodeTable
+ at: { 0 "NUL" . 2r0010 "ctrl" }
+ put: { 32 "SPACE". 2 "ctrl" }.
+ KeyDecodeTable
+ at: { 0 "NUL" . 2r0011 "ctrl+shift" }
+ put: { 32 "SPACE". 2r0011 "ctrl+shift" }.!
- 0 "NUL" to: 27 "ESC" do: [:control |
- KeyDecodeTable
- at: { control . 2r0010 "ctrl" }
- put: { control bitOr: 16r60 "+96" . 2 "ctrl" }.
- KeyDecodeTable
- at: { control . 2r0011 "ctrl+shift" }
- put: { control bitOr: 16r40 "+64" . 2r0011 "ctrl+shift" }].!

Item was added:
+ ----- Method: EventSensor class>>installVirtualKeyTable (in category 'class initialization') -----
+ installVirtualKeyTable
+
+ VirtualKeyTable := Dictionary newFrom: (
+ Smalltalk windowSystemName
+ caseOf: {
+ ['Windows'] -> [self virtualKeysOnWindows].
+ ['Win32' "older VMs"] -> [self virtualKeysOnWindows].
+ ['Aqua'] -> [self virtualKeysOnMacOS].
+ ['X11'] -> [self virtualKeysOnX11].
+ ['RiscOS'] -> [{}].
+ ['Quartz'] -> [{}].
+ } otherwise: [{}]).
+
+ "Shift 8 bits to not overwrite virtual-key mappings from above."
+ self mapControlKeysToCommandKeys ifTrue: [
+ VirtualKeyTable
+ at: (2r0010 "ctrl" bitShift: 8)
+ put: (2r1010 "cmd+ctrl").
+ VirtualKeyTable
+ at: (2r0011 "ctrl+shift" bitShift: 8)
+ put: (2r1011 "cmd+ctrl+shift")].
+
+ self mapAltKeysToOptionKeys ifTrue: [
+ VirtualKeyTable
+ at: (2r1000 "cmd/alt" bitShift: 8)
+ put: (2r1100 "cmd/alt+opt").
+ VirtualKeyTable
+ at: (2r1001 "cmd/alt+shift" bitShift: 8)
+ put: (2r1101 "cmd/alt+opt+shift")].!

Item was changed:
  ----- Method: EventSensor class>>mapAltKeysToOptionKeys: (in category 'preferences') -----
  mapAltKeysToOptionKeys: aBooleanOrNil
 
  aBooleanOrNil = self mapAltKeysToOptionKeys
  ifTrue: [^ self].
 
  aBooleanOrNil
  ifNil: [
  KeyDecodePreferences
  removeKey: #mapAltKeysToOptionKeys]
  ifNotNil: [
  KeyDecodePreferences
  at: #mapAltKeysToOptionKeys
  put: aBooleanOrNil].
 
+ self installKeyDecodeTable.
+ self installVirtualKeyTable.!
- self installKeyDecodeTable.!

Item was changed:
  ----- Method: EventSensor class>>mapControlKeysToCommandKeys: (in category 'preferences') -----
  mapControlKeysToCommandKeys: aBooleanOrNil
 
  aBooleanOrNil
  ifNil: [
  KeyDecodePreferences
  removeKey: #mapControlKeysToCommandKeys]
  ifNotNil: [
  KeyDecodePreferences
  at: #mapControlKeysToCommandKeys
  put: aBooleanOrNil].
 
+ self installKeyDecodeTable.
+ self installVirtualKeyTable.!
- self installKeyDecodeTable.!

Item was added:
+ ----- Method: EventSensor class>>simplifyVirtualKeyCodes (in category 'preferences') -----
+ simplifyVirtualKeyCodes
+ <preference: 'Simplify virtual-key codes'
+ categoryList: #(keyboard events input)
+ description: 'On some platforms, virtual-key codes (aka. scan codes) depend on the language setting (e.g. US, UK, DE), which is unkown to Squeak. Enable this preference to simplify overlapping codes to common symbols #squeak1, #squeak2, etc., which improves cross-platform compatibility but reduces the number of keys available for different handlers.'
+ type: #Boolean>
+
+ ^ KeyDecodePreferences
+ at: #simplifyVirtualKeyCodes
+ ifAbsent: [true]!

Item was added:
+ ----- Method: EventSensor class>>simplifyVirtualKeyCodes: (in category 'preferences') -----
+ simplifyVirtualKeyCodes: aBooleanOrNil
+
+ aBooleanOrNil = self simplifyVirtualKeyCodes
+ ifTrue: [^ self].
+
+ aBooleanOrNil
+ ifNil: [
+ KeyDecodePreferences
+ removeKey: #simplifyVirtualKeyCodes]
+ ifNotNil: [
+ KeyDecodePreferences
+ at: #simplifyVirtualKeyCodes
+ put: aBooleanOrNil].
+
+ self installVirtualKeyTable.!

Item was removed:
- ----- Method: EventSensor class>>startUp (in category 'system startup') -----
- startUp
-
- Smalltalk platformName = 'Mac OS'
- ifTrue: [
- self mapAltKeysToOptionKeys: false.
- self mapControlKeysToCommandKeys: false]
- ifFalse: [
- self mapAltKeysToOptionKeys: true.
- self mapControlKeysToCommandKeys: true].
-
- self default startUp.!

Item was added:
+ ----- Method: EventSensor class>>startUp: (in category 'system startup') -----
+ startUp: resuming
+
+ resuming ifTrue: [
+ Smalltalk platformName = 'Mac OS'
+ ifTrue: [
+ self mapAltKeysToOptionKeys: false.
+ self mapControlKeysToCommandKeys: false]
+ ifFalse: [
+ self mapAltKeysToOptionKeys: true.
+ self mapControlKeysToCommandKeys: true].
+ self installVirtualKeyTable ].
+
+ self default startUp.!

Item was added:
+ ----- Method: EventSensor class>>virtualKeyAt: (in category 'virtual keys') -----
+ virtualKeyAt: keyCode
+ "Answers a representation for the (non-modifier) key, which should be consistent across platforms considering its cause."
+
+ ^ self virtualKeyTable at: keyCode!

Item was added:
+ ----- Method: EventSensor class>>virtualKeyTable (in category 'virtual keys') -----
+ virtualKeyTable
+
+ ^ VirtualKeyTable ifNil: [self installVirtualKeyTable]!

Item was added:
+ ----- Method: EventSensor class>>virtualKeysOnMacOS (in category 'virtual keys') -----
+ virtualKeysOnMacOS
+ "Based on Carbon's Events.h -- https://snipplr.com/view/42797"
+
+ ^ {
+ 16r00 -> $A. "#'kVK_ANSI_A'"
+ 16r01 -> $S. "#'kVK_ANSI_S'"
+ 16r02 -> $D. "#'kVK_ANSI_D'"
+ 16r03 -> $F. "#'kVK_ANSI_F'"
+ 16r04 -> $H. "#'kVK_ANSI_H'"
+ 16r05 -> $G. "#'kVK_ANSI_G'"
+ 16r06 -> $Z. "#'kVK_ANSI_Z'"
+ 16r07 -> $X. "#'kVK_ANSI_X'"
+ 16r08 -> $C. "#'kVK_ANSI_C'"
+ 16r09 -> $V. "#'kVK_ANSI_V'"
+ 16r0B -> $B. "#'kVK_ANSI_B'"
+ 16r0C -> $Q. "#'kVK_ANSI_Q'"
+ 16r0D -> $W. "#'kVK_ANSI_W'"
+ 16r0E -> $E. "#'kVK_ANSI_E'"
+ 16r0F -> $R. "#'kVK_ANSI_R'"
+ 16r10 -> $Y. "#'kVK_ANSI_Y'"
+ 16r11 -> $T. "#'kVK_ANSI_T'"
+ 16r12 -> $1. "#'kVK_ANSI_1'"
+ 16r13 -> $2. "#'kVK_ANSI_2'"
+ 16r14 -> $3. "#'kVK_ANSI_3'"
+ 16r15 -> $4. "#'kVK_ANSI_4'"
+ 16r16 -> $6. "#'kVK_ANSI_6'"
+ 16r17 -> $5. "#'kVK_ANSI_5'"
+ 16r18 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'kVK_ANSI_Equal']).
+ 16r19 -> $9. "#'kVK_ANSI_9'"
+ 16r1A -> $7. "#'kVK_ANSI_7'"
+ 16r1B -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Minus']).
+ 16r1C -> $8. "#'kVK_ANSI_8'"
+ 16r1D -> $0. "#'kVK_ANSI_0'"
+ 16r1E -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'kVK_ANSI_RightBracket']).
+ 16r1F -> $O. "#'kVK_ANSI_O'"
+ 16r20 -> $U. "#'kVK_ANSI_U'"
+ 16r21 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_LeftBracket']).
+ 16r22 -> $I. "#'kVK_ANSI_I'"
+ 16r23 -> $P. "#'kVK_ANSI_P'"
+ 16r25 -> $L. "#'kVK_ANSI_L'"
+ 16r26 -> $J. "#'kVK_ANSI_J'"
+ 16r27 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak3] ifFalse: [#'kVK_ANSI_Quote']).
+ 16r28 -> $K. "#'kVK_ANSI_K'"
+ 16r29 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Semicolon']).
+ 16r2A -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Backslash']).
+ 16r2B -> #squeakComma. "#'kVK_ANSI_Comma'"
+ 16r2C -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Slash']).
+ 16r2D -> $N. "#'kVK_ANSI_N'"
+ 16r2E -> $M. "#'kVK_ANSI_M'"
+ 16r2F -> #squeakPeriod. "#'kVK_ANSI_Period'"
+ 16r32 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak4] ifFalse: [#'kVK_ANSI_Grave']).
+ 16r41 -> #numDec. "#'kVK_ANSI_KeypadDecimal'"
+ 16r43 -> #numMul. "#'kVK_ANSI_KeypadMultiply'"
+ 16r45 -> #numAdd. "#'kVK_ANSI_KeypadPlus'"
+ 16r47 -> #numClr. "#'kVK_ANSI_KeypadClear'"
+ 16r4B -> #numDiv. "#'kVK_ANSI_KeypadDivide'"
+ 16r4C -> (self simplifyVirtualKeyCodes ifTrue: [Character return] ifFalse: [Character enter]). "#'kVK_ANSI_KeypadEnter'"
+ 16r4E -> #numSub. "#'kVK_ANSI_KeypadMinus'"
+ 16r51 -> #numEqu. "#'kVK_ANSI_KeypadEquals'"
+ 16r52 -> #num0. "#'kVK_ANSI_Keypad0'"
+ 16r53 -> #num1. "#'kVK_ANSI_Keypad1'"
+ 16r54 -> #num2. "#'kVK_ANSI_Keypad2'"
+ 16r55 -> #num3. "#'kVK_ANSI_Keypad3'"
+ 16r56 -> #num4. "#'kVK_ANSI_Keypad4'"
+ 16r57 -> #num5. "#'kVK_ANSI_Keypad5'"
+ 16r58 -> #num6. "#'kVK_ANSI_Keypad6'"
+ 16r59 -> #num7. "#'kVK_ANSI_Keypad7'"
+ 16r5B -> #num8. "#'kVK_ANSI_Keypad8'"
+ 16r5C -> #num9. "#'kVK_ANSI_Keypad9'"
+ 16r24 -> Character return. "#'kVK_Return'"
+ 16r30 -> Character tab. "#'kVK_Tab'"
+ 16r31 -> Character space. "#'kVK_Space'"
+ 16r33 -> Character backspace. "#'kVK_Delete'"
+ 16r35 -> Character escape. "#'kVK_Escape'"
+ 16r36 -> #command. "#'kVK_RightCommand'"
+ 16r37 -> #command. "#'kVK_Command'"
+ 16r38 -> #shift. "#'kVK_Shift'"
+ 16r39 -> #capsLock. "#'kVK_CapsLock'"
+ 16r3A -> #option. "#'kVK_Option'"
+ 16r3B -> #control. "#'kVK_Control'"
+ 16r3C -> #shift. "#'kVK_RightShift'"
+ 16r3D -> #option. "#'kVK_RightOption'"
+ 16r3E -> #control. "#'kVK_RightControl'"
+ 16r3F -> #'kVK_Function'.
+ 16r40 -> #F17. "#'kVK_F17'"
+ 16r48 -> #'kVK_VolumeUp'.
+ 16r49 -> #'kVK_VolumeDown'.
+ 16r4A -> #'kVK_Mute'.
+ 16r4F -> #F18. "#'kVK_F18'"
+ 16r50 -> #F19. "#'kVK_F19'"
+ 16r5A -> #F20. "#'kVK_F20'"
+ 16r60 -> #F5. "#'kVK_F5'"
+ 16r61 -> #F6. "#'kVK_F6'"
+ 16r62 -> #F7. "#'kVK_F7'"
+ 16r63 -> #F3. "#'kVK_F3'"
+ 16r64 -> #F8. "#'kVK_F8'"
+ 16r65 -> #F9. "#'kVK_F9'"
+ 16r67 -> #F11. "#'kVK_F11'"
+ 16r69 -> #F13. "#'kVK_F13'"
+ 16r6A -> #F16. "#'kVK_F16'"
+ 16r6B -> #F14. "#'kVK_F14'"
+ 16r6D -> #F10. "#'kVK_F10'"
+ 16r6F -> #F12. "#'kVK_F12'"
+ 16r71 -> #F15. "#'kVK_F15'"
+ 16r72 -> #help. "#'kVK_Help'"
+ 16r73 -> Character home. "#'kVK_Home'"
+ 16r74 -> Character pageUp. "#'kVK_PageUp'"
+ 16r75 -> Character delete. "#'kVK_ForwardDelete'"
+ 16r76 -> #F4. "#'kVK_F4'"
+ 16r77 -> Character end. "#'kVK_End'"
+ 16r78 -> #F2. "#'kVK_F2'"
+ 16r79 -> Character pageDown. "#'kVK_PageDown'"
+ 16r7A -> #F1. "#'kVK_F1'"
+ 16r7B -> Character arrowLeft. "#'kVK_LeftArrow'"
+ 16r7C -> Character arrowRight. "#'kVK_RightArrow'"
+ 16r7D -> Character arrowDown. "#'kVK_DownArrow'"
+ 16r7E -> Character arrowUp. "#'kVK_UpArrow'"
+ 16r0A -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ISO_Section']).
+ 16r5D -> #'kVK_JIS_Yen'.
+ 16r5E -> #'kVK_JIS_Underscore'.
+ 16r5F -> #'kVK_JIS_KeypadComma'.
+ 16r66 -> #'kVK_JIS_Eisu'.
+ 16r68 -> #'kVK_JIS_Kana'.
+ }!

Item was added:
+ ----- Method: EventSensor class>>virtualKeysOnWindows (in category 'virtual keys') -----
+ virtualKeysOnWindows
+ "https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
+
+ Tweaked to Windows 10 Version 20H2 (Build 19042.928)
+ Microsoft Surface Pro 6 (GERMAN)"
+
+ ^ {
+
+ 16r01 -> Character home. "#'VK_HOME'" "Overshadows #'VK_LBUTTON' --- Left mouse button"
+ 16r02 -> #'VK_RBUTTON'. "Right mouse button"
+ 16r03 -> #'VK_CANCEL'. "Control-break processing"
+ 16r04 -> Character end. "#'VK_END'" "Overshadows #'VK_MBUTTON' --- Middle mouse button"
+ 16r05 -> Character insert. "#'VK_INSERT'" "Overshadows #'VK_XBUTTON1' --- X1 mouse button"
+ 16r06 -> #'VK_XBUTTON2'. "X2 mouse button"
+ 16r07 -> nil.
+ 16r08 -> Character backspace. "#'VK_BACK'"
+ 16r09 -> Character tab. "#'VK_TAB'"
+ 16r0A -> nil.
+ 16r0B -> Character pageUp. "#'VK_PRIOR'" "PAGE UP key"
+ 16r0C -> Character pageDown. "#'VK_NEXT'" "PAGE DOWN key --- overshadows #'VK_CLEAR'"
+ 16r0D -> Character return. "#'VK_RETURN'" "ENTER key"
+ 16r0E -> nil.
+ 16r0F -> nil.
+ 16r10 -> #shift. "#'VK_SHIFT'"
+ 16r11 -> (self mapControlKeysToCommandKeys ifTrue: [#command] ifFalse: [#control]). "#'VK_CONTROL'"
+ 16r12 -> (self mapAltKeysToOptionKeys ifTrue: [#option] ifFalse: [#command "aka. #alt"]). "#'VK_MENU'"
+ 16r13 -> #'VK_PAUSE'.
+ 16r14 -> #capsLock. "#'VK_CAPITAL'"
+ 16r15 -> #'VK_KANA'. "IME Kana/Hangul mode"
+ 16r16 -> #'VK_IME_ON'. "IME on"
+ 16r17 -> #'VK_JUNJA'. "IMA Junja mode"
+ 16r18 -> #'VK_FINAL'. "IME final mode"
+ 16r19 -> #'VK_KANJI'. "IME Kanji/Hanja mode"
+ 16r1A -> #'VK_IME_OFF'. "IME off"
+ 16r1B -> Character escape. "#'VK_ESCAPE'"
+ 16r1C -> Character arrowLeft. "#'VK_LEFT'" "LEFT ARROW. Overshadows #'VK_CONVERT' --- IME convert"
+ 16r1D -> Character arrowRight. "#'VK_RIGHT'" "RIGHT ARROW. Overshadows 'VK_NONCONVERT' --- IME nonconvert"
+ 16r1E -> Character arrowUp. "#'VK_UP'" "UP ARROW. Overshadows #'VK_ACCEPT' --- IME accept"
+ 16r1F -> Character arrowDown. "#'VK_DOWN'" "DOWN ARROW. Overshadows #'VK_MODECHANGE' --- IME mode change request"
+ 16r20 -> Character space. "#'VK_SPACE'" "SPACEBAR"
+ 16r21 -> #'VK_PRIOR'. "PAGE UP key. Not needed. See 16r0B"
+ 16r22 -> #'VK_NEXT'. "PAGE DOWN key. Not needed. See 16r0C"
+ 16r23 -> #'VK_END'. "Not needed. See 16r04"
+ 16r24 -> #'VK_HOME'. "Not needed. See 16r01"
+ 16r25 -> #'VK_LEFT'. "LEFT ARROW. Not needed. See 16r1C"
+ 16r26 -> #'VK_UP'. "UP ARROW. Not needed. See 16r1E"
+ 16r27 -> #'VK_RIGHT'. "RIGHT ARROW. Not needed. See 16r1D"
+ 16r28 -> #'VK_DOWN'. "DOWN ARROW. Not needed. See 16r1F"
+ 16r29 -> #'VK_SELECT'.
+ 16r2A -> #'VK_PRINT'.
+ 16r2B -> #'VK_EXECUTE'.
+ 16r2C -> #'VK_SNAPSHOT'. "PRINT SCREEN key"
+ 16r2D -> #'VK_INSERT'. "Not needed. See 16r05"
+ 16r2E -> #F16. "#'VK_F16' swapped with #'VK_DELETE'. See 16r7F"
+ 16r2F -> #help. "#'VK_HELP'"
+ 16r30 -> $0.
+ 16r31 -> $1.
+ 16r32 -> $2.
+ 16r33 -> $3.
+ 16r34 -> $4.
+ 16r35 -> $5.
+ 16r36 -> $6.
+ 16r37 -> $7.
+ 16r38 -> $8.
+ 16r39 -> $9.
+ 16r3A -> nil.
+ 16r3B -> nil.
+ 16r3C -> nil.
+ 16r3D -> nil.
+ 16r3E -> nil.
+ 16r3F -> nil.
+ 16r40 -> nil.
+ 16r41 -> $A.
+ 16r42 -> $B.
+ 16r43 -> $C.
+ 16r44 -> $D.
+ 16r45 -> $E.
+ 16r46 -> $F.
+ 16r47 -> $G.
+ 16r48 -> $H.
+ 16r49 -> $I.
+ 16r4A -> $J.
+ 16r4B -> $K.
+ 16r4C -> $L.
+ 16r4D -> $M.
+ 16r4E -> $N.
+ 16r4F -> $O.
+ 16r50 -> $P.
+ 16r51 -> $Q.
+ 16r52 -> $R.
+ 16r53 -> $S.
+ 16r54 -> $T.
+ 16r55 -> $U.
+ 16r56 -> $V.
+ 16r57 -> $W.
+ 16r58 -> $X.
+ 16r59 -> $Y.
+ 16r5A -> $Z.
+ 16r5B -> #'VK_LWIN'. "Left Windows key"
+ 16r5C -> #'VK_RWIN'. "Right windows key"
+ 16r5D -> #'VK_APPS'. "Applications key"
+ 16r5E -> nil.
+ 16r5F -> #'VK_SLEEP'. "Computer Sleep Key"
+ 16r60 -> #num0. "#'VK_NUMPAD0'"
+ 16r61 -> #num1. "#'VK_NUMPAD1'"
+ 16r62 -> #num2. "#'VK_NUMPAD2'"
+ 16r63 -> #num3. "#'VK_NUMPAD3'"
+ 16r64 -> #num4. "#'VK_NUMPAD4'"
+ 16r65 -> #num5. "#'VK_NUMPAD5'"
+ 16r66 -> #num6. "#'VK_NUMPAD6'"
+ 16r67 -> #num7. "#'VK_NUMPAD7'"
+ 16r68 -> #num8. "#'VK_NUMPAD8'"
+ 16r69 -> #num9. "#'VK_NUMPAD9'"
+ 16r6A -> #numMul. "#'VK_MULTIPLY'"
+ 16r6B -> #numAdd. "#'VK_ADD'"
+ 16r6C -> #'VK_SEPARATOR'.
+ 16r6D -> #numSub. "#'VK_SUBTRACT'"
+ 16r6E -> #numDec. "#'VK_DECIMAL'"
+ 16r6F -> #numDiv. "#'VK_DIVIDE'"
+ 16r70 -> #F1. "#'VK_F1'"
+ 16r71 -> #F2. "#'VK_F2'"
+ 16r72 -> #F3. "#'VK_F3'"
+ 16r73 -> #F4. "#'VK_F4'"
+ 16r74 -> #F5. "#'VK_F5'"
+ 16r75 -> #F6. "#'VK_F6'"
+ 16r76 -> #F7. "#'VK_F7'"
+ 16r77 -> #F8. "#'VK_F8'"
+ 16r78 -> #F9. "#'VK_F9'"
+ 16r79 -> #F10. "#'VK_F10'"
+ 16r7A -> #F11. "#'VK_F11'"
+ 16r7B -> #F12. "#'VK_F12'"
+ 16r7C -> #F13. "#'VK_F13'"
+ 16r7D -> #F14. "#'VK_F14'"
+ 16r7E -> #F15. "#'VK_F15'"
+ 16r7F -> Character delete. "#'VK_DELETE' swapped with #'VK_F16'. See 16r2E"
+ 16r80 -> #F17. "#'VK_F17'"
+ 16r81 -> #F18. "#'VK_F18'"
+ 16r82 -> #F19. "#'VK_F19'"
+ 16r83 -> #F20. "#'VK_F20'"
+ 16r84 -> #F21. "#'VK_F21'"
+ 16r85 -> #F22. "#'VK_F22'"
+ 16r86 -> #F23. "#'VK_F23'"
+ 16r87 -> #F24. "#'VK_F24'"
+ 16r88 -> nil.
+ 16r89 -> nil.
+ 16r8A -> nil.
+ 16r8B -> nil.
+ 16r8C -> nil.
+ 16r8D -> nil.
+ 16r8E -> nil.
+ 16r8F -> nil.
+ 16r90 -> #'VK_NUMLOCK'.
+ 16r91 -> #'VK_SCROLL'.
+ 16r92 -> nil.
+ 16r93 -> nil.
+ 16r94 -> nil.
+ 16r95 -> nil.
+ 16r96 -> nil.
+ 16r97 -> nil.
+ 16r98 -> nil.
+ 16r99 -> nil.
+ 16r9A -> nil.
+ 16r9B -> nil.
+ 16r9C -> nil.
+ 16r9D -> nil.
+ 16r9E -> nil.
+ 16r9F -> nil.
+ 16rA0 -> #'VK_LSHIFT'.
+ 16rA1 -> #'VK_RSHIFT'.
+ 16rA2 -> #'VK_LCONTROL'.
+ 16rA3 -> #'VK_RCONTROL'.
+ 16rA4 -> #'VK_LMENU'.
+ 16rA5 -> #'VK_RMENU'.
+ 16rA6 -> #'VK_BROWSER_BACK'.
+ 16rA7 -> #'VK_BROWSER_FORWARD'.
+ 16rA8 -> #'VK_BROWSER_REFRESH'.
+ 16rA9 -> #'VK_BROWSER_STOP'.
+ 16rAA -> #'VK_BROWSER_SEARCH'.
+ 16rAB -> #'VK_BROWSER_FAVORITES'.
+ 16rAC -> #'VK_BROWSER_HOME'.
+ 16rAD -> #'VK_VOLUME_MUTE'.
+ 16rAE -> #'VK_VOLUME_DOWN'.
+ 16rAF -> #'VK_VOLUME_UP'.
+ 16rB0 -> #'VK_MEDIA_NEXT_TRACK'.
+ 16rB1 -> #'VK_MEDIA_PREV_TRACK'.
+ 16rB2 -> #'VK_MEDIA_STOP'.
+ 16rB3 -> #'VK_MEDIA_PLAY_PAUSE'.
+ 16rB4 -> #'VK_LAUNCH_MAIL'.
+ 16rB5 -> #'VK_LAUNCH_MEDIA_SELECT'.
+ 16rB6 -> #'VK_LAUNCH_APP1'.
+ 16rB7 -> #'VK_LAUNCH_APP2'.
+ 16rB8 -> nil.
+ 16rB9 -> nil.
+
+ 16rBA -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_1']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ;: key"
+
+ 16rBB -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'VK_OEM_PLUS']).
+ "For any country/region, the + key -- mt. Haha. You wish."
+
+ 16rBC -> #squeakComma. "#'VK_OEM_COMMA'" "For any country/region, the , key"
+
+ 16rBD -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_MINUS']).
+ "For any country/region, the - key"
+
+ 16rBE -> #squeakPeriod. "#'VK_OEM_PERIOD'" "For any country/region, the . key"
+
+ 16rBF -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_2']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the /? key"
+
+ 16rC0 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_3']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `~ key'"
+
+ 16rC1 -> nil.
+ 16rC2 -> nil.
+ 16rC3 -> nil.
+ 16rC4 -> nil.
+ 16rC5 -> nil.
+ 16rC6 -> nil.
+ 16rC7 -> nil.
+ 16rC8 -> nil.
+ 16rC9 -> nil.
+ 16rCA -> nil.
+ 16rCB -> nil.
+ 16rCC -> nil.
+ 16rCD -> nil.
+ 16rCE -> nil.
+ 16rCF -> nil.
+ 16rD0 -> nil.
+ 16rD1 -> nil.
+ 16rD2 -> nil.
+ 16rD3 -> nil.
+ 16rD4 -> nil.
+ 16rD5 -> nil.
+ 16rD6 -> nil.
+ 16rD7 -> nil.
+ 16rD8 -> nil.
+ 16rD9 -> nil.
+ 16rDA -> nil.
+
+ 16rDB -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_4']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the [{ key"
+
+ 16rDC -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_5']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the \| key"
+
+ 16rDD -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'VK_OEM_6']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ]} key"
+
+ 16rDE -> (self simplifyVirtualKeyCodes ifTrue: [#squeak3] ifFalse: [#'VK_OEM_7']).
+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the single-quote/double-quote key"
+
+ 16rDF -> #'VK_OEM_8'.
+ "Used for miscellaneous characters; it can vary by keyboard."
+
+ 16rE0 -> nil.
+ 16rE1 -> nil.
+
+ 16rE2 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak4] ifFalse: [#'VK_OEM_102']).
+ "Either the angle bracket key or the backslash key on the RT 102-key keyboard"
+
+ 16rE3 -> nil.
+ 16rE4 -> nil.
+ 16rE5 -> #'VK_PROCESSKEY'. "IME PROCESS key"
+ 16rE6 -> nil.
+ 16rE7 -> #'VK_PACKET'. "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods."
+ 16rE8 -> nil.
+ 16rE9 -> nil.
+ 16rEA -> nil.
+ 16rEB -> nil.
+ 16rEC -> nil.
+ 16rED -> nil.
+ 16rEE -> nil.
+ 16rEF -> nil.
+ 16rF0 -> nil.
+ 16rF1 -> nil.
+ 16rF2 -> nil.
+ 16rF3 -> nil.
+ 16rF4 -> nil.
+ 16rF5 -> nil.
+ 16rF6 -> #'VK_ATTN'.
+ 16rF7 -> #'VK_CRSEL'.
+ 16rF8 -> #'VK_EXSEL'.
+ 16rF9 -> #'VK_EREOF'. "Erase EOF key"
+ 16rFA -> #'VK_PLAY'.
+ 16rFB -> #'VK_ZOOM'.
+ 16rFC -> #'VK_NONAME'. "Reserved"
+ 16rFD -> #'VK_PA1'.
+ 16rFE -> #'VK_OEM_CLEAR'. "Clear key"
+
+ }!

Item was added:
+ ----- Method: EventSensor class>>virtualKeysOnX11 (in category 'virtual keys') -----
+ virtualKeysOnX11
+ "Based on the OSVM X11 code as of 202104182333"
+ "https://code.woboq.org/kde/include/X11/keysymdef.h.html"
+
+ "!!!!!! There are non-printable control keys for keyDown events on X11. Sigh."
+ self flag: #todo. "Linux VM is broken. We need scancodes but we get actual character codes. It is really hard to determine physical keys from that."
+ ^ {
+
+ "Regular ASCII"
+ 16r41 -> $A.
+ 16r42 -> $B.
+ 16r43 -> $C.
+ 16r44 -> $D.
+ 16r45 -> $E.
+ 16r46 -> $F.
+ 16r47 -> $G.
+ 16r48 -> $H.
+ 16r49 -> $I.
+ 16r4A -> $J.
+ 16r4B -> $K.
+ 16r4C -> $L.
+ 16r4D -> $M.
+ 16r4E -> $N.
+ 16r4F -> $O.
+ 16r50 -> $P.
+ 16r51 -> $Q.
+ 16r52 -> $R.
+ 16r53 -> $S.
+ 16r54 -> $T.
+ 16r55 -> $U.
+ 16r56 -> $V.
+ 16r57 -> $W.
+ 16r58 -> $X.
+ 16r59 -> $Y.
+ 16r5A -> $Z.
+
+ "Regular ASCII - numbers"
+ 16r30 -> $0.
+ 16r31 -> $1.
+ 16r32 -> $2.
+ 16r33 -> $3.
+ 16r34 -> $4.
+ 16r35 -> $5.
+ 16r36 -> $6.
+ 16r37 -> $7.
+ 16r38 -> $8.
+ 16r39 -> $9.
+
+ "Mapped to uppercase when SHIFT is pressed ... sigh ..."
+ 16r61 -> $A.
+ 16r62 -> $B.
+ 16r63 -> $C.
+ 16r64 -> $D.
+ 16r65 -> $E.
+ 16r66 -> $F.
+ 16r67 -> $G.
+ 16r68 -> $H.
+ 16r69 -> $I.
+ 16r6A -> $J.
+ 16r6B -> $K.
+ 16r6C -> $L.
+ 16r6D -> $M.
+ 16r6E -> $N.
+ 16r6F -> $O.
+ 16r70 -> $P.
+ 16r71 -> $Q.
+ 16r72 -> $R.
+ 16r73 -> $S.
+ 16r74 -> $T.
+ 16r75 -> $U.
+ 16r76 -> $V.
+ 16r77 -> $W.
+ 16r78 -> $X.
+ 16r79 -> $Y.
+ 16r7A -> $Z.
+
+ "most common non-printable control characters"
+ 16r01 -> Character home.
+ 16r03 -> Character enter.
+ 16r04 -> Character end.
+ 16r05 -> Character insert.
+ 16r08 -> Character backspace.
+ 16r09 -> Character tab.
+ 16r0B -> Character pageUp.
+ 16r0C -> Character pageDown.
+ 16r0D -> Character return.
+ 16r1B -> Character escape.
+ 16r1C -> Character arrowLeft.
+ 16r1D -> Character arrowRight.
+ 16r1E -> Character arrowUp.
+ 16r1F -> Character arrowDown.
+ 16r20 -> Character space.
+
+ 16r7F -> Character delete.
+
+ "Physical modifier keys"
+ 16rF7 -> (self mapAltKeysToOptionKeys ifTrue: [#option] ifFalse: [#command "aka. #alt"]). "#'XK_Alt_L'"
+ 16rFE -> #shift. "#'XK_Shift_R'"
+ 16rFF -> #shift. "#'XK_Shift_L'."
+ 16rFA ->  (self mapControlKeysToCommandKeys ifTrue: [#command] ifFalse: [#control]). "#'XK_Control_R'"
+ 16rFB ->  (self mapControlKeysToCommandKeys ifTrue: [#command] ifFalse: [#control]). "#'XK_Control_L'."
+ 16rFD -> #capsLock. "#'XK_Caps_Lock'."
+
+ "Try to make sense of some other key characters. Hmpf."
+ 16r22 -> #squeak1.
+ 16r23 -> #squeak1.
+ 16r27 -> #squeak1.
+ 16r2D -> #squeak1.
+ 16r2F -> #squeak1.
+ 16r3A -> #squeak1.
+ 16r3B -> #squeak1.
+ 16r3C -> #squeak1.
+ 16r3E -> #squeak1.
+ 16r3F -> #squeak1.
+ 16r5B -> #squeak1.
+ 16r5C -> #squeak1.
+ 16r5E -> #squeak1.
+ 16r5F -> #squeak1.
+ 16r60 -> #squeak1.
+ 16r7B -> #squeak1.
+ 16r7C -> #squeak1.
+ 16r7E -> #squeak1.
+ 16rC2 -> #squeak1.
+ 16rC3 -> #squeak1.
+
+ 16r2A -> #squeak2.
+ 16r2B -> #squeak2.
+ 16r3D -> #squeak2.
+ 16r5D -> #squeak2.
+ 16r7D -> #squeak2.
+
+ 16r2C -> #squeakComma.
+ 16r2E -> #squeakPeriod.
+
+ }!

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 (e.g., map ctrl -> 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]]
+ ifFalse: ["Replace modifiers for virtual keys. (keyUp/keyDown)"
+ VirtualKeyTable
+ at: ((evt at: 5) bitShift: 8)
+ ifPresent: [:a | evt at: 5 put: a]].
- at: 5 put: a second]].
  self queueEvent: evt.
  self processKeyboardEvent: evt .
  ^self ].
 
  "Handle all events other than Keyboard or Mouse."
  self queueEvent: evt.
  !

Item was changed:
+ (PackageInfo named: 'Kernel') postscript: 'EventSensor initialize..
+ EventSensor startUp..'!
- (PackageInfo named: 'Kernel') postscript: 'EventSensor initialize.
- EventSensor startUp.'!