tag:forum.world.st,2006:forum-45488
Nabble - Squeak - Dev
2024-03-28T04:19:17Z
The general-purpose Squeak developers list
tag:forum.world.st,2006:post-5133076
UITextEdit
2024-01-03T18:25:12Z
2024-01-03T18:25:12Z
nathant
I am trying to create a text editor in squeak that has some extra features. I really want to be able to preserve the layout so it uses the scrollbar instead of manually wrapping the text.
<br/><br/>It looks as if TextEditMorph has more control over that and PluggableTextMorph but I have trouble using
<br/>those objects.
<br/><br/>Does anyone know or have any suggestions on how to make the UITextEdit comply with wrapping? Or another suggestion on text wrapping?
tag:forum.world.st,2006:post-5132211
📣❗❗❗ ANNOUNCEMENT: FORUM.WORLD.ST ABANDONED - NEW FORUM LINK ❗❗❗
2023-07-03T10:54:52Z
2023-07-03T10:54:52Z
Christoph Thiede
Hi all,
<br/><br/>as mentioned <a href="http://forum.world.st/Mirror-at-forum-world-st-not-up-to-date-Please-use-mailing-lists-directly-td5130692.html" target="_top" rel="nofollow" link="external">earlier</a>, <b>forum.world.st/this Nabble instance is no longer up to date.</b> Communication continues on the mailing list, and you can also participate using our new forum:
<br/><br/> * <b>HyperKitty (recommended):</b> <a href="https://lists.squeakfoundation.org/archives/list/squeak-dev@lists.squeakfoundation.org/" target="_top" rel="nofollow" link="external">https://lists.squeakfoundation.org/archives/list/squeak-dev@lists.squeakfoundation.org/</a><br/> * <b>pipermail</b> (old mirror, NOT up to date): <a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/" target="_top" rel="nofollow" link="external">http://lists.squeakfoundation.org/pipermail/squeak-dev/</a><br/> * <b><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk" target="_top" rel="nofollow" link="external">Squeak Inbox Talk:</a></b> Directly access the mailing list from your image (-:
<br/><br/>Also, if you are already subscribed to the mailing list, <a href="https://lists.squeakfoundation.org/archives/list/squeak-dev@lists.squeakfoundation.org/thread/WYGAF674I7EFCNV3EYLKXCOUMWF2HS2W/" target="_top" rel="nofollow" link="external">please reclaim your mail address on HyperKitty.
<br/><br/>Find more on <a href="https://squeak.org/community/" target="_top" rel="nofollow" link="external">https://squeak.org/community/</a>.
<br/><br/>Squeak is alive! Happy Squeaking! :-)
<br/><br/>Best,
<br/>Christoph
<div class="signature weak-color">
Carpe Squeak!
</div>
tag:forum.world.st,2006:post-56093
Fwd: Sieve of Eratosthenes
2006-10-09T21:01:26Z
2006-10-09T21:01:26Z
Gil Egozi
<span class="gmail_quote"></span>Hi,<br> I am resending this since i wan't a member, and the message is still somewhere in moderation-land.<br><br> after looking at Ramon's version i noticed the java version isn't returning the primes, so we can remove the last select:
<br>this cuts time in half down close to: 500<br><br>Integer>>sieveOfEratosthenes<br> "generates primes up to self, educational algorithm, not for
<br>production use"<br> | primes |<br> primes := ByteArray new: self.<br> 2 to: self do: [:each | <br> (primes at: each) = 0 ifTrue: [each + each to: self<br> by: each do: [:notPrime | <br>
primes at: notPrime put: 1]]].<br><br>"-------------"<br>SmalltalkImage current snapshot: true andQuit: false<br>
Smalltalk garbageCollect.<br>
Smalltalk garbageCollect.<br>
Smalltalk garbageCollect. "force full garbage collect"<br>
Time millisecondsToRun: [1000000 sieveOfEratosthenes].<br>
<br>Gil <br><span class="sg"><br>-- <br>Many people would sooner die than think; In fact, they do so.<br> -- Bertrand Russell
</span><br clear="all"><br>
<br /><br/>
tag:forum.world.st,2006:post-5131096
Hire for small task in squeak smalltalk - please connect me if relevant for you
2022-11-26T08:31:33Z
2022-11-26T08:31:33Z
mikelewis123
Hi all,
<br/>I'm looking for a squeak small talk developer for a small task.
<br/>Please don't hesitate to connect me and I will elaborate more.
<br/>Thanks:)
tag:forum.world.st,2006:post-5131057
Fun .image file for squeak 3.0!
2022-10-06T14:32:17Z
2022-10-06T14:32:17Z
NewHope68
lmao <b>hilarious</b><img class='smiley' src='/images/smiley/anim_claps.gif' /><br/><br/><a href="https://rapidshare.io/Gql/REXX-IMAGE-3.0.zip" target="_top" rel="nofollow" link="external">https://rapidshare.io/Gql/REXX-IMAGE-3.0.zip</a>
<div class="signature weak-color">
now THATS perfect!
</div>
tag:forum.world.st,2006:post-5126833
The Trunk: System-cmm.1214.mcz
2021-02-05T21:25:20Z
2021-02-05T21:25:20Z
commits-2
Chris Muller uploaded a new version of System to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/System-cmm.1214.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/System-cmm.1214.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: System-cmm.1214
<br/>Author: cmm
<br/>Time: 5 February 2021, 10:09:05.179247 pm
<br/>UUID: d6f968d9-a638-42ef-89ef-d37af0f31ffd
<br/>Ancestors: System-mt.1213
<br/><br/>Patch the patcher. Smalltalk run: permits the patching of a production system without having to resort to running a custom image, but when the patch.st file has read-only status in the OS, FileStream class>>#fileNamed:do: can't open it, because it tries to open for read/write. But rather htan signal an error, it silently does nothing (wow), leaving the system unpatched.
<br/> Patch files can and should be read-only anyway, so use DirectoryEntryFile>>#readStreamDo:.
<br/><br/>=============== Diff against System-mt.1213 ===============
<br/><br/>Item was changed:
<br/> ----- Method: SmalltalkImage>>patchSystem (in category 'command line') -----
<br/> patchSystem
<br/> 'patch.st' asDirectoryEntry ifNotNil:
<br/> [ : patchEntry | patchEntry modificationTime > Smalltalk imageName asDirectoryEntry modificationTime
<br/> ifTrue:
<br/> [ Notification signal: 'Patching system...'.
<br/>+ patchEntry readStreamDo: [ : stream | stream fileIn ] ]
<br/>- FileStream
<br/>- fileNamed: 'patch.st'
<br/>- do:
<br/>- [ : stream | stream fileIn ] ]
<br/> ifFalse: [ self error: 'patch.st file is older than the image file. Aborting.' ] ]!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130657
Still Squeak alive?
2021-08-18T03:31:00Z
2021-09-03T08:29:38Z
CalmoSoft1960
<b>CONTENTS DELETED</b>
<div class="weak-color">The author has deleted this message.</div>
tag:forum.world.st,2006:post-5130692
Mirror at forum.world.st not up-to-date! Please use mailing lists directly
2021-09-15T10:38:47Z
2021-09-15T10:38:47Z
marcel.taeumel
Hi all --
<br/><br/>This Nabble instance is no longer connected to our mailing lists (<a href="http://lists.squeakfoundation.org/" target="_top" rel="nofollow" link="external">http://lists.squeakfoundation.org/</a>). Please re-enable mail delivery in your settings (<a href="http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/squeak-dev" target="_top" rel="nofollow" link="external">http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/squeak-dev</a>).
<br/><br/>Even if not subscribed, you can browse the lists easily such as squeak-dev here: <a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/" target="_top" rel="nofollow" link="external">http://lists.squeakfoundation.org/pipermail/squeak-dev/</a><br/><br/>Best,
<br/>Marcel
tag:forum.world.st,2006:post-5130679
FFI not working in 5.3
2021-09-01T19:05:33Z
2021-09-01T19:05:33Z
LawsonEnglish
Is there something wrong with FFI and Squeak 5.3?
<br/><br/>I tried to run this install and got all sorts of errors:
<br/><br/><br/>(Installer repository: '<a href="http://source.squeak.org/FFI'" target="_top" rel="nofollow" link="external">http://source.squeak.org/FFI'</a>)
<br/> install: 'FFI-Pools';
<br/> install: 'FFI-Kernel';
<br/> install: 'FFI-Tests';
<br/> install: 'FFI-Examples'.
tag:forum.world.st,2006:post-5104939
The Trunk: Collections-pre.857.mcz
2019-10-04T02:04:32Z
2019-10-04T02:04:32Z
commits-2
Patrick Rein uploaded a new version of Collections to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Collections-pre.857.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Collections-pre.857.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Collections-pre.857
<br/>Author: pre
<br/>Time: 4 October 2019, 11:04:30.363303 am
<br/>UUID: 5ef00b65-3884-c445-b276-0cc01f0b10a1
<br/>Ancestors: Collections-pre.856
<br/><br/>Adds startOfHeader to Character, adds empty abstract implementations of scanFrom:, writeScanOn: to TextAttribute to allow for Texts which include TextAttributes which do not implement serialization to still be serialized, adds a comment to these methods.
<br/><br/>=============== Diff against Collections-pre.856 ===============
<br/><br/>Item was added:
<br/>+ ----- Method: Character class>>startOfHeader (in category 'accessing untypeable characters') -----
<br/>+ startOfHeader
<br/>+
<br/>+ ^ self value: 1 !
<br/><br/>Item was added:
<br/>+ ----- Method: TextAttribute class>>scanFrom: (in category 'fileIn/Out') -----
<br/>+ scanFrom: strm
<br/>+ "Read the text attribute properties from the stream. When this method has
<br/>+ been called the concrete TextAttribute class has already been selected via
<br/>+ scanCharacter. (see TextAttribute class>>#newFrom:).
<br/>+ For writing the format see TextAttribute>>#writeScanOn:"!
<br/><br/>Item was added:
<br/>+ ----- Method: TextAttribute>>writeScanOn: (in category 'fileIn/fileOut') -----
<br/>+ writeScanOn: strm
<br/>+ "Implement this method for a text attribute to define how it it should be written
<br/>+ to a serialized form of a text object. The form should correspond to the source
<br/>+ file format, i.e. use a scan character to denote its subclass.
<br/>+ As TextAttributes are stored in RunArrays, this method is mostly called from RunArray>>#write scan.
<br/>+ For reading the written information see TextAttribute class>>#scanFrom:"
<br/>+
<br/>+ "Do nothing because of abstract class"!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130644
Hand me a sketch of this morph
2021-08-11T17:16:31Z
2021-08-11T17:16:31Z
Jeremy L.
I much appreciate how far the Etoys support has come in squeak 5.3. I'm very much a 'high level' user of squeak and always found Etoys as sort of supercharged Hypercard and enjoy using it in that way. While exploring the unofficial updates in the 'back door squeak' in Etoys 5, I found a very useful morphic option called 'Hand Me Sketch of This Morph', which creates a bitmap copy of the object complete with transparencies if it's a non-square graphic and places it at the mouse cursor. It was never officially released into Etoys, but I found I used it quite a lot in doing graphics work and it helped speed up screen updates for more intensive graphics stuff I was doing since moving around a bitmap is much faster than drawing a bunch of, say, overlapping polygons and other geometric objects in which a lot of the drawing to update those things is all for naught: if graphic object overlaps another graphic object, they're both drawn completely, and thus moving them wastes a lot of drawing time. If they're not going to change but be moving around the screen, one could contain them into a playfield which, as I understand it, keeps the playfield 'data' but actually moves it by copying the playfield as a simple graphic. All this said, once I'm happy with a graphic, I tend to make a bitmap sketch out of it and handling the transparencies of grabbing a sketch takes a couple of tedious steps. "Hand me a sketch of this morph" was a huge time saver in this respect and quickly freed up cycles (is that the right way to say it?) for things that don't have to do with drawing a lot of objects.
<br/><br/>I guess what I'm getting at is that I'm making a case for this method from the Etoys prototype trunk to be added somewhere down the line into Squeak and hope that this can happen. If I was more Smalltalk savvy, I'd add it into Montecello or something. I understand my uses for Squeak are probably niche and such feature would be seen as obscure, but I suppose it never hurts to bring attention to it and ask. :)
<br/><br/>Thanks, Squeak crew.
<br/><br/>
tag:forum.world.st,2006:post-5130575
[ANN] Squeak Inbox Talk - bringing squeak-dev into your image
2021-07-08T19:16:18Z
2021-07-08T19:16:18Z
Christoph Thiede
Hi all! :-)<br>
<br>
I'm very excited to announce a new tool to you today that aims to make the Squeak development cycle a bit easier for all of us. Introducing <b>Squeak Inbox Talk,</b> which allows you as Squeak contributors and maintainers to review and discuss new features for Squeak directly in your image!<br>
<br>
<b>Installation:</b><br>
Install the latest Trunk updates first.<br>
<pre><code> Metacello new
baseline: 'SqueakInboxTalk';
repository: 'github://hpi-swa-lab/squeak-inbox-talk:main';
load.</code></pre>
After the installation, in the main docking bar, choose "Squeak Inbox Talk" from the Apps menu, click Refresh, and there you go!<br>
Alternatively, you can download a ready-to-use image here: <a href="https://github.com/hpi-swa-lab/squeak-inbox-talk/releases" target="_top" rel="nofollow" link="external">https://github.com/hpi-swa-lab/squeak-inbox-talk/releases</a><br>
In [1] you can find the open-source GitHub repository, including a project board and some theoretical background.<br>
<b>Your feedback</b> is especially helpful for my research <b>before 2021-07-19</b> (but still appreciated later very much).<br>
<br>
Maybe you have already experienced at least one of the following troubles in the past:<br>
1. Tedious navigation on the list: Where has this patch gone? Can someone remember where we were discussing this funky thing recently?<br>
2. High entry barrier for new contributors: You need to sign up on the mailing list to follow discussions.<br>
3. Hard review process: Notifications and discussions appear in your email client, but if you want to check out some code, you will switch to your image, of course.<br>
<br>
In the last months, I have been trying to solve these and other issues. Now I'm inviting you to figure out whether I have been successful! Squeak Inbox Talk allows you to interact with all relevant artifacts right in Squeak, including emails as well as Monticello contributions. It comes with a free-text search and several powerful filters for aspects such as packages, review state of a contribution, and your personal involvement. These filters should make it easier to survey certain domains, gain a better understanding of the connection between inbox versions, or keep track of your own proposals.<br>
<br>
Please give it a try and return feedback! As one possible starting point, you could search for "terminate" to recapitulate Jaromir's recent efforts on Process. I had the great opportunity to run this project in the course of a seminar at HPI, and the luck to be guided by Marcel while doing so. In a few weeks, I will present the project internally, and your thoughts and feedback will of course be very helpful for my evaluation. Needless to say, I'm also looking forward to making the tool even more convenient for you. :-)<br>
<br>
Thank you so much in advance!<br>
<br>
Best,<br>
Christoph<br>
<br>
<hr>
<br>
APPENDIX: How does it work?<br>
<br>
Basically, Squeak Inbox Talk is implemented by reusing and assembling together the following existing solutions: Squeak History [2], a project originally developed by Marcel (mt) that scrapes and processes all mailing list conversations from the pipermail archives [3]; the SMTPClient in Squeak [5] for sending messages; and the Monticello infrastructure, which remains the heart of our development workflow. Optionally, further components such as IMAPClient [4] might follow later. On top of this, Squeak Inbox Talk adds a convenient layer for exploring and filtering conversations and contributions.<br>
<br>
[1] <a href="https://github.com/hpi-swa-lab/squeak-inbox-talk" target="_top" rel="nofollow" link="external">https://github.com/hpi-swa-lab/squeak-inbox-talk</a><br>
[2] <a href="https://github.com/hpi-swa/squeak-history" target="_top" rel="nofollow" link="external">https://github.com/hpi-swa/squeak-history</a><br>
[3] <a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/" target="_top" rel="nofollow" link="external">http://lists.squeakfoundation.org/pipermail/squeak-dev/</a><br>
[4] <a href="https://github.com/hpi-swa-teaching/IMAPClient" target="_top" rel="nofollow" link="external">https://github.com/hpi-swa-teaching/IMAPClient</a><br>
[5] This mail was sent from Squeak Inbox Talk using the latest version of the SMTPClient. Yeah, it's actually still alive and doing well! =D<br>
<br>
<hr>
<i><b>Disclaimer:</b> I have manually copied this message to enable for linking purposes. At the time of writing, <a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-June/215852.html" target="_top" rel="nofollow" link="external">Nabble is still out of sync.</a></i>
<div class="signature weak-color">
Carpe Squeak!
</div>
tag:forum.world.st,2006:post-5130562
Still Squeak alive?
2021-07-02T07:00:21Z
2021-07-02T07:00:21Z
CalmoSoft
Hello All,
<br/><br/>Still Squeak alive because the last update on download page was on 6/6/2021?
<br/><br/>Greetings,
<br/>Gal Zsolt
<br/>(~ CalmoSoft ~)
<br/>
tag:forum.world.st,2006:post-5130450
Debian tarball updates?
2021-06-16T10:34:09Z
2021-06-16T10:34:09Z
timrowledge
Is anyone out there interested in, and able to spend the time, to try to sort out an update of the Debian tarball stuff?
<br/><br/>A long time ago we went through some considerable effort to get Squeak into the system and it seems to have languished ever since. It would make us look somewhat more contemporary if we could get an updated package built and inserted.
<br/><br/>Please, if you can help, let us know.
<br/><br/>tim
<br/>--
<br/>tim Rowledge; <a href="/user/SendEmail.jtp?type=node&node=5130450&i=0" target="_top" rel="nofollow" link="external">[hidden email]</a>; <a href="http://www.rowledge.org/tim" target="_top" rel="nofollow" link="external">http://www.rowledge.org/tim</a><br/>Strange OpCodes: RWD: Rewind Disk
<br/><br/><br/><br/>
tag:forum.world.st,2006:post-5122760
The Inbox: Morphic-ct.1690.mcz
2020-09-30T17:42:25Z
2020-09-30T17:42:25Z
commits-2
A new version of Morphic was added to project The Inbox:
<br/><a href="http://source.squeak.org/inbox/Morphic-ct.1690.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/inbox/Morphic-ct.1690.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-ct.1690
<br/>Author: ct
<br/>Time: 1 October 2020, 2:42:17.443188 am
<br/>UUID: 58a1128e-5547-4236-bc03-0c1f1366bb7b
<br/>Ancestors: Morphic-eem.1686
<br/><br/>Fixes display invalidation in PluggableListMorph when displayed during updating the list contents.
<br/><br/>To avoid recursive #getList sends, since Morphic-mt.1576, the list variable has been cleaned up before sending #getFullList/#getFilteredList. However, in some cases the list morph is redrawn while the #getList operation is being performed, for example if the model code shows a system progress bar (e.g. when loading/refreshing code in Monticello). In the past, this led to drawing artifacts during the list update.
<br/><br/>To avoid these artifacts, this version implements the list update as an atomic operation by storing the previous list contents in the variable previousStableList while recomputing the list. In addition, if #getList is curtailed, the previous list contents are restored (which is especially helpful during debugging).
<br/><br/>=============== Diff against Morphic-eem.1686 ===============
<br/><br/>Item was changed:
<br/> ScrollPane subclass: #PluggableListMorph
<br/>+ instanceVariableNames: 'list fullList modelToView viewToModel getListSelector getListSizeSelector getListElementSelector getIndexSelector setIndexSelector keystrokeActionSelector autoDeselect lastKeystrokeTime lastKeystrokes lastClickTime doubleClickSelector handlesBasicKeys potentialDropRow hoverRow listMorph keystrokePreviewSelector priorSelection getIconSelector getHelpSelector previousStableList'
<br/>- instanceVariableNames: 'list fullList modelToView viewToModel getListSelector getListSizeSelector getListElementSelector getIndexSelector setIndexSelector keystrokeActionSelector autoDeselect lastKeystrokeTime lastKeystrokes lastClickTime doubleClickSelector handlesBasicKeys potentialDropRow hoverRow listMorph keystrokePreviewSelector priorSelection getIconSelector getHelpSelector'
<br/> classVariableNames: 'ClearFilterAutomatically ClearFilterDelay FilterableLists FlashOnErrors HighlightHoveredRow HighlightPreSelection MenuRequestUpdatesSelection'
<br/> poolDictionaries: ''
<br/> category: 'Morphic-Pluggable Widgets'!
<br/>
<br/> !PluggableListMorph commentStamp: 'mt 10/12/2019 11:04' prior: 0!
<br/> I am a list widget that uses the change/update mechanism to display model data as a vertical arrangement of (maybe formatted) strings and icons in a scroll pane.
<br/>
<br/> When I am in keyboard focus, type in a letter (or several letters quickly) to go to the next item that begins with that letter. If you enabled the "filterable lists" preference, I will hide all items that do not match the filter.
<br/>
<br/> Special keys (arrow up/down, page up/down, home, end) are also supported.!
<br/><br/>Item was changed:
<br/> ----- Method: PluggableListMorph>>getList (in category 'model access - cached') -----
<br/> getList
<br/>+ "Answer the (maybe filtered) list to be displayed. Cached result, see #updateList. If the list needs to be updated, do this atomically."
<br/>+
<br/>+ list = #locked ifTrue: [
<br/>+ "The list is already being updated at the moment but needs to be accessed again during the update. To avoid recursion, the update is implemented as an atomic operation. This can happen, for example, when the model fetches data that opens the system progress bar which then will redraw periodically."
<br/>+ ^ previousStableList ifNil: #()].
<br/>- "Answer the (maybe filtered) list to be displayed. Cached result, see #updateList."
<br/>-
<br/> ^ list ifNil: [
<br/>+ list := #locked.
<br/>- list := #(). "To make this call safe when re-entering it while fetching the list. This can happen, for example, when the model fetches data that opens the system progress bar which then will redraw periodically."
<br/> list := self filterableList
<br/> ifTrue: [self getFilteredList]
<br/> ifFalse: [self getFullList].
<br/> self updateListMorph.
<br/> list]!
<br/><br/>Item was changed:
<br/> ----- Method: PluggableListMorph>>updateListFilter (in category 'updating') -----
<br/> updateListFilter
<br/>
<br/> | selection |
<br/> selection := self selectionIndex = 0 "Avoid fetching #getList here."
<br/> ifTrue: [nil]
<br/> ifFalse: [self selection].
<br/>
<br/>+ previousStableList := list.
<br/>+ [list := nil.
<br/>- list := nil.
<br/> modelToView := Dictionary new.
<br/> viewToModel := Dictionary new.
<br/>
<br/>+ self getList] ensure: [
<br/>+ list ifNil: [list := previousStableList].
<br/>+ previousStableList := nil].
<br/>- self getList.
<br/>
<br/> "Try to restore the last selection."
<br/> selection ifNotNil: [self selection: selection].!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130494
The Trunk: Morphic-mt.1774.mcz
2021-06-17T23:42:50Z
2021-06-17T23:42:50Z
commits-2
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Morphic-mt.1774.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Morphic-mt.1774.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-mt.1774
<br/>Author: mt
<br/>Time: 18 June 2021, 8:42:44.573904 am
<br/>UUID: 1e89964d-814b-4345-b3e6-fef6a4f54cc0
<br/>Ancestors: Morphic-mt.1773
<br/><br/>Complements Kernel-mt.1403.
<br/><br/>Adds #key to all keyboard events to be used as a cross-platform identifier (or object) for virtual keys. Works the same for keyUp, keyDown, and keystroke events.
<br/><br/>Adds #keyCode, which is the low-level version of #key. For example, #keyCode would answer 29 while #key would answer "Character arrowRight" - an actual object that identifies the physically pressed key.
<br/><br/>Use #key when implementing keyboard shortcuts. Feel free to check for modifiers or keyUp/Down/Stroke depending on your use case.
<br/><br/>Note that this change relies on the fact that #keyDown will ALWAYS come before a #keystroke. Always. And that #keyDown events will carry the virtual key-code (or scan code), not a higher-level (Unicode) character for text input.
<br/><br/>For more background information see <a href="http://forum.world.st/Please-try-out-Cross-platform-mapping-for-virtual-key-codes-tp5129188.html" target="_top" rel="nofollow" link="external">http://forum.world.st/Please-try-out-Cross-platform-mapping-for-virtual-key-codes-tp5129188.html</a><br/><br/>=============== Diff against Morphic-mt.1773 ===============
<br/><br/>Item was changed:
<br/> Morph subclass: #HandMorph
<br/>+ instanceVariableNames: 'mouseFocus keyboardFocus eventListeners mouseListeners keyboardListeners eventCaptureFilters mouseCaptureFilters keyboardCaptureFilters mouseClickState mouseOverHandler targetOffset lastMouseEvent lastKeyDownEvent damageRecorder cacheCanvas cachedCanvasHasHoles temporaryCursor temporaryCursorOffset hardwareCursor hasChanged savedPatch userInitials lastEventBuffer genieGestureProcessor keyboardInterpreter externalDropMorph'
<br/>- instanceVariableNames: 'mouseFocus keyboardFocus eventListeners mouseListeners keyboardListeners eventCaptureFilters mouseCaptureFilters keyboardCaptureFilters mouseClickState mouseOverHandler targetOffset lastMouseEvent damageRecorder cacheCanvas cachedCanvasHasHoles temporaryCursor temporaryCursorOffset hardwareCursor hasChanged savedPatch userInitials lastEventBuffer genieGestureProcessor keyboardInterpreter externalDropMorph'
<br/> classVariableNames: 'CompositionWindowManager DoubleClickTime DragThreshold EventStats MinimalWheelDelta NewEventRules NormalCursor PasteBuffer SendMouseWheelToKeyboardFocus ShowEvents SynthesizeMouseWheelEvents'
<br/> poolDictionaries: 'EventSensorConstants'
<br/> category: 'Morphic-Kernel'!
<br/>
<br/> !HandMorph commentStamp: '<historical>' prior: 0!
<br/> The cursor may be thought of as the HandMorph. The hand's submorphs hold anything being carried by dragging.
<br/>
<br/> There is some minimal support for multiple hands in the same world.!
<br/><br/>Item was changed:
<br/> ----- Method: HandMorph>>generateKeyboardEvent: (in category 'private events') -----
<br/> generateKeyboardEvent: evtBuf
<br/> "Generate the appropriate mouse event for the given raw event buffer"
<br/>
<br/>+ | buttons modifiers type pressType stamp keyValue keyCode |
<br/>- | buttons modifiers type pressType stamp keyValue |
<br/> stamp := evtBuf second.
<br/> stamp = 0 ifTrue: [stamp := Sensor eventTimeNow].
<br/> pressType := evtBuf fourth.
<br/> pressType = EventKeyDown ifTrue: [type := #keyDown].
<br/> pressType = EventKeyUp ifTrue: [type := #keyUp].
<br/> pressType = EventKeyChar ifTrue: [type := #keystroke].
<br/> modifiers := evtBuf fifth.
<br/> buttons := (modifiers bitShift: MouseEvent numButtons) bitOr: (lastMouseEvent buttons bitAnd: MouseEvent anyButton).
<br/> type = #keystroke
<br/>+ ifTrue: [
<br/>+ keyValue := (self keyboardInterpreter nextCharFrom: EventSensor default firstEvt: evtBuf) asInteger.
<br/>+ keyCode := lastKeyDownEvent keyValue]
<br/>+ ifFalse: [keyValue := keyCode := evtBuf third].
<br/>- ifTrue: [keyValue := (self keyboardInterpreter nextCharFrom: Sensor firstEvt: evtBuf) asInteger]
<br/>- ifFalse: [keyValue := evtBuf third].
<br/> ^ KeyboardEvent new
<br/> setType: type
<br/> buttons: buttons
<br/> position: self position
<br/> keyValue: keyValue
<br/>+ keyCode: keyCode
<br/> hand: self
<br/> stamp: stamp.
<br/> !
<br/><br/>Item was changed:
<br/> ----- Method: HandMorph>>handleEvent: (in category 'events-processing') -----
<br/> handleEvent: unfilteredEvent
<br/>
<br/> | filteredEvent |
<br/> owner ifNil: [^ unfilteredEvent "not necessary but good style -- see Morph >> #handleEvent:"].
<br/>
<br/> self logEvent: unfilteredEvent.
<br/>
<br/> "Mouse-over events occur really, really, really often. They are kind of the heart beat of the Morphic UI process."
<br/> unfilteredEvent isMouseOver ifTrue: [^ self sendMouseEvent: unfilteredEvent].
<br/>
<br/> self showEvent: unfilteredEvent.
<br/> self sendListenEvents: unfilteredEvent.
<br/>
<br/> filteredEvent := self sendFilterEventCapture: unfilteredEvent for: nil.
<br/> "filteredEvent := unfilteredEvent" " <-- use this to disable global capture filters"
<br/>
<br/> filteredEvent wasIgnored ifTrue: [
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/> filteredEvent isWindowEvent ifTrue: [
<br/> self sendEvent: filteredEvent focus: nil.
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/>+ filteredEvent isKeyboard ifTrue: [
<br/>+ filteredEvent isKeyDown ifTrue: [lastKeyDownEvent := filteredEvent].
<br/>- filteredEvent isKeyboard ifTrue:[
<br/> self sendKeyboardEvent: filteredEvent.
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/> filteredEvent isDropEvent ifTrue:[
<br/> self sendEvent: filteredEvent focus: nil.
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/> filteredEvent isMouse ifFalse: [
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/> " ********** MOUSE EVENT *********** "
<br/>
<br/> lastMouseEvent := filteredEvent.
<br/>
<br/> "Check for pending drag or double click operations."
<br/> mouseClickState ifNotNil:[
<br/> (mouseClickState handleEvent: filteredEvent from: self) ifFalse:[
<br/> "Possibly dispatched #click: or something and will not re-establish otherwise"
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent]].
<br/>
<br/> filteredEvent isMouseWheel ifTrue: [
<br/> self class sendMouseWheelToKeyboardFocus
<br/> ifFalse: [self sendMouseEvent: filteredEvent]
<br/> ifTrue: [self sendEvent: filteredEvent focus: self keyboardFocus clear: [self keyboardFocus: nil]].
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/> filteredEvent isMove ifTrue:[
<br/> self position: filteredEvent position.
<br/> self sendMouseEvent: filteredEvent.
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent].
<br/>
<br/> "Issue a synthetic move event if we're not at the position of the event"
<br/> self flag: #bug. "mt: Incompatible with how #mouseMove: is handled when #wantsEveryMouseMove: answers false. Handler might think that #mouseDown: was already received. For example, TextEditor and HaloMorph will issue drags in their #mouseMove: based on old data. That is, the first #mouseMove: appears to come before #mouseDown: while actually sent due to #moveToEvent:."
<br/> filteredEvent position = self position
<br/> ifFalse: [self moveToEvent: filteredEvent].
<br/>
<br/> "Drop submorphs on button events"
<br/> self hasSubmorphs
<br/> ifTrue:[self dropMorphs: filteredEvent]
<br/> ifFalse:[self sendMouseEvent: filteredEvent].
<br/>
<br/> self mouseOverHandler processMouseOver: lastMouseEvent.
<br/> ^ filteredEvent "not necessary but good style -- see Morph >> #handleEvent:" !
<br/><br/>Item was changed:
<br/> ----- Method: HandMorph>>initForEvents (in category 'initialization') -----
<br/> initForEvents
<br/> mouseOverHandler := nil.
<br/> lastMouseEvent := MouseEvent new setType: #mouseMove position: 0@0 buttons: 0 hand: self.
<br/>+ lastKeyDownEvent := KeyboardEvent new setType: #keyDown buttons: 0 position: 0@0 keyValue: 0 hand: self stamp: 0.
<br/> lastEventBuffer := {1. 0. 0. 0. 0. 0. nil. nil}.
<br/> self resetClickState.
<br/> self addKeyboardCaptureFilter: self. "to convert unusual VM events"!
<br/><br/>Item was changed:
<br/> ----- Method: HandMorph>>logEvent: (in category 'events-debugging') -----
<br/> logEvent: anEvent
<br/> "Update statistics for processed events."
<br/>
<br/> EventStats ifNil: [EventStats := IdentityDictionary new].
<br/> EventStats at: #count put: (EventStats at: #count ifAbsent: [0]) + 1.
<br/> EventStats at: anEvent type put: (EventStats at: anEvent type ifAbsent: [0]) + 1.!
<br/><br/>Item was changed:
<br/> UserInputEvent subclass: #KeyboardEvent
<br/>+ instanceVariableNames: 'keyValue keyCode'
<br/>- instanceVariableNames: 'keyValue'
<br/> classVariableNames: ''
<br/> poolDictionaries: ''
<br/> category: 'Morphic-Events'!
<br/><br/>Item was changed:
<br/>+ ----- Method: KeyboardEvent>>asMorph (in category 'morphic/tools - converting') -----
<br/>- ----- Method: KeyboardEvent>>asMorph (in category 'converting') -----
<br/> asMorph
<br/> "Answers a graphical reprsentation for this keyboard event. Does not work for keyUp and keyDown because we do not have platform-specific mapping tables for the key codes."
<br/>
<br/>+ | box color arrow |
<br/>- | box color |
<br/> box := Morph new
<br/> color: Color transparent;
<br/> layoutPolicy: TableLayout new;
<br/> listDirection: #leftToRight;
<br/> hResizing: #shrinkWrap;
<br/> vResizing: #shrinkWrap;
<br/> cellGap: 2;
<br/> yourself.
<br/> color := self userInterfaceTheme get: #textColor for: #PluggableButtonMorph.
<br/>
<br/>+ self physicalModifiers
<br/>- self labelsForPhysicalModifiers
<br/> do: [:modifier |
<br/>+ box addMorphBack: (ToolIcons keyboardButtonLabeled: modifier capitalized dyed: color) asMorph.
<br/>- box addMorphBack: (ToolIcons keyboardButtonLabeled: modifier dyed: color) asMorph.
<br/> box addMorphBack: (('+' asText addAttribute: (TextColor color: color); asMorph) lock)].
<br/>
<br/>+ "Visualize arrow keys."
<br/>+ arrow := self key.
<br/>+ (arrow isCharacter and: [arrow asciiValue between: 28 and: 31]) ifTrue: [
<br/>+ box addMorphBack: (ToolIcons keyboardButtonLabeled: (
<br/>+ ScrollBar
<br/>+ arrowOfDirection: (#(left right top bottom) at: arrow asciiValue - 27)
<br/>+ size: Preferences standardButtonFont height
<br/>+ color: Color black) dyed: color) asMorph.
<br/>+ ^ box].
<br/>- (self keyValue between: 28 and: 31)
<br/>- ifTrue: [ "arrow keys"
<br/>- box addMorphBack: (ToolIcons keyboardButtonLabeled: (
<br/>- ScrollBar
<br/>- arrowOfDirection: (#(left right top bottom) at: self keyValue - 27)
<br/>- size: Preferences standardButtonFont height
<br/>- color: Color black) dyed: color) asMorph.
<br/>- ^ box].
<br/>
<br/> box addMorphBack: (ToolIcons
<br/>+ keyboardButtonLabeled: self physicalKey asString capitalized
<br/>- keyboardButtonLabeled: (self isKeystroke
<br/>- ifTrue: [self labelForPhysicalKeyStroke]
<br/>- ifFalse: [self labelForPhysicalKeyDown])
<br/> dyed: color) asMorph.
<br/>
<br/> ^ box!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>key (in category 'keyboard') -----
<br/>+ key
<br/>+ "Answers a representation for the (non-modifier) key, which should be consistent across platforms considering its cause."
<br/>+
<br/>+ ^ EventSensor virtualKeyAt: keyCode!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>keyCode (in category 'keyboard') -----
<br/>+ keyCode
<br/>+ "Answers the virtual-key code (or scan code) for this event."
<br/>+
<br/>+ ^ keyCode!
<br/><br/>Item was removed:
<br/>- ----- Method: KeyboardEvent>>labelForPhysicalKeyDown (in category 'printing') -----
<br/>- labelForPhysicalKeyDown
<br/>- "#keyDown and #keyUp -- needs platform-specific mapping for virtual key codes"
<br/>-
<br/>- ^ 'VK-0x', (self keyValue printPaddedWith: $0 to: 2 base: 16)!
<br/><br/>Item was removed:
<br/>- ----- Method: KeyboardEvent>>labelForPhysicalKeyStroke (in category 'printing') -----
<br/>- labelForPhysicalKeyStroke
<br/>-
<br/>- ^ (self keyValue <= 32 or: [self keyValue = 127])
<br/>- ifFalse: [
<br/>- self keyCharacter asUppercase asString]
<br/>- ifTrue: [
<br/>- (self controlKeyPressed and: [self keyValue < 28 "no arrows or space"])
<br/>- ifTrue: [
<br/>- "Most likely a physical key with a readable (uppercase) label. Be aware that this cannot cover the cases where the physical contro key was pressed together with the CTRL modifier."
<br/>- (self keyValue bitOr: 16r40) asCharacter asString "+64"]
<br/>- ifFalse: [
<br/>- self keyValue caseOf: {
<br/>- [ 1 ] -> [ 'Home' translated ].
<br/>- [ 4 ] -> [ 'End' translated ].
<br/>- [ 5 ] -> [ 'Insert' translated ].
<br/>- [ 8 ] -> [ 'Backspace' translated ].
<br/>- [ 9 ] -> [ 'Tab' ].
<br/>- [ 10 ] -> [ 'LF' ].
<br/>- [ 11 ] -> [ 'PageUp' translated ].
<br/>- [ 12 ] -> [ 'PageDown' translated ].
<br/>- [ 13 ] -> [ 'Return' translated "CR" ].
<br/>- [ 27 ] -> [ 'Esc' ].
<br/>- [ 32 ] -> [ 'Space' translated ].
<br/>- [ 127 ] -> [ 'Del' translated ].
<br/>- } otherwise: [
<br/>- 'ASCII-', (self keyValue printPaddedWith: $0 to: 2 base: 10)]]]!
<br/><br/>Item was removed:
<br/>- ----- Method: KeyboardEvent>>labelsForPhysicalModifiers (in category 'printing') -----
<br/>- labelsForPhysicalModifiers
<br/>- "Help users understand the physical modifier keys that where involved in this event. Note that, due to historical reasons, the SHIFT modifier comes first on macOS but last on other platforms."
<br/>-
<br/>- | result |
<br/>- result := OrderedCollection new.
<br/>-
<br/>- Smalltalk platformName = 'Mac OS'
<br/>- ifTrue: [
<br/>- self shiftPressed ifTrue: [result add: 'Shift'].
<br/>- self controlKeyPressed ifTrue: [result add: 'Ctrl'].
<br/>- self optionKeyPressed ifTrue: [result add: 'Opt'].
<br/>- self commandKeyPressed ifTrue: [result add: 'Cmd']]
<br/>- ifFalse: [ "Linux/Windows"
<br/>- self controlKeyPressed
<br/>- ifTrue: [result add: 'Ctrl']
<br/>- ifFalse: [
<br/>- Smalltalk platformName = 'Win32'
<br/>- ifTrue: [
<br/>- (self commandKeyPressed or: [self optionKeyPressed])
<br/>- ifTrue: [result add: 'Alt']]
<br/>- ifFalse: ["Linux/ARM"
<br/>- self commandKeyPressed
<br/>- ifTrue: [result add: 'Alt']
<br/>- ifFalse: [self optionKeyPressed
<br/>- ifTrue: [
<br/>- result add: 'Strg'.
<br/>- result add: 'Alt']]]].
<br/>- self shiftPressed ifTrue: [result add: 'Shift']].
<br/>- ^ result!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>physicalKey (in category 'morphic/tools - accessing') -----
<br/>+ physicalKey
<br/>+
<br/>+ ^ self key
<br/>+ ifNil: ['VK-0x', (self keyCode printPaddedWith: $0 to: 2 base: 16)]
<br/>+ ifNotNil: [:key |
<br/>+ (#(control command option) includes: key)
<br/>+ ifTrue: [ "Similar to #physicalModifiers"
<br/>+ Smalltalk platformName = 'Mac OS'
<br/>+ ifTrue: [key]
<br/>+ ifFalse: [
<br/>+ self controlKeyPressed
<br/>+ ifTrue: [(self optionKeyPressed and: [self commandKeyPressed])
<br/>+ ifTrue: [#alt "Linux/X11"]
<br/>+ ifFalse: [#control]]
<br/>+ ifFalse: [#alt]]]
<br/>+ ifFalse: [
<br/>+ (key isCharacter
<br/>+ ifTrue: [(Character constantNameFor: key) ifNil: [key]]
<br/>+ ifFalse: [key]) ]]!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>physicalModifiers (in category 'morphic/tools - accessing') -----
<br/>+ physicalModifiers
<br/>+ "Help users understand the physical modifier keys that where involved in this event. Note that, due to historical reasons, the SHIFT modifier comes first on macOS but last on other platforms."
<br/>+
<br/>+ | result |
<br/>+ result := OrderedCollection new.
<br/>+
<br/>+ Smalltalk platformName = 'Mac OS'
<br/>+ ifTrue: [
<br/>+ self shiftPressed ifTrue: [result add: #shift].
<br/>+ self controlKeyPressed ifTrue: [result add: #ctrl].
<br/>+ self optionKeyPressed ifTrue: [result add: #opt].
<br/>+ self commandKeyPressed ifTrue: [result add: #cmd]]
<br/>+ ifFalse: [ "Linux/Windows"
<br/>+ self controlKeyPressed
<br/>+ ifTrue: [result add: #ctrl]
<br/>+ ifFalse: [
<br/>+ Smalltalk platformName = 'Win32'
<br/>+ ifTrue: [
<br/>+ (self commandKeyPressed or: [self optionKeyPressed])
<br/>+ ifTrue: [result add: #alt]]
<br/>+ ifFalse: ["Linux/ARM"
<br/>+ self commandKeyPressed
<br/>+ ifTrue: [result add: #alt]
<br/>+ ifFalse: [self optionKeyPressed
<br/>+ ifTrue: [
<br/>+ result add: #ctrl.
<br/>+ result add: #alt]]]].
<br/>+ self shiftPressed ifTrue: [result add: #shift]].
<br/>+ ^ result!
<br/><br/>Item was changed:
<br/> ----- Method: KeyboardEvent>>printKeyStringOn: (in category 'printing') -----
<br/> printKeyStringOn: aStream
<br/> "Print a readable string representing the receiver on a given stream"
<br/>
<br/> | kc inBrackets firstBracket keyString |
<br/> kc := self keyCharacter.
<br/> inBrackets := false.
<br/> firstBracket := [ inBrackets ifFalse: [ aStream nextPut: $<. inBrackets := true ]].
<br/>+ self modifiers do: [:modifier |
<br/>+ firstBracket value. aStream nextPutAll: modifier; nextPutAll: '-' ].
<br/>- self controlKeyPressed ifTrue: [ firstBracket value. aStream nextPutAll: 'Ctrl-' ].
<br/>- self commandKeyPressed ifTrue: [ firstBracket value. aStream nextPutAll: 'Cmd-' ].
<br/>- self optionKeyPressed ifTrue: [ firstBracket value. aStream nextPutAll: 'Opt-' ].
<br/>- self shiftPressed ifTrue: [ firstBracket value. aStream nextPutAll: 'Shift-' ].
<br/>
<br/>+ keyString := (Character constantNameFor: kc)
<br/>+ ifNil: [String with: kc].
<br/>- keyString := (kc caseOf: {
<br/>- [ Character space ] -> [ 'space' ].
<br/>- [ Character tab ] -> [ 'tab' ].
<br/>- [ Character cr ] -> [ 'cr' ].
<br/>- [ Character lf ] -> [ 'lf' ].
<br/>- [ Character enter ] -> [ 'enter' ].
<br/>-
<br/>- [ Character backspace ] -> [ 'backspace' ].
<br/>- [ Character delete ] -> [ 'delete' ].
<br/>-
<br/>- [ Character escape ] -> [ 'escape' ].
<br/>-
<br/>- [ Character arrowDown ] -> [ 'down' ].
<br/>- [ Character arrowUp ] -> [ 'up' ].
<br/>- [ Character arrowLeft ] -> [ 'left' ].
<br/>- [ Character arrowRight ] -> [ 'right' ].
<br/>-
<br/>- [ Character end ] -> [ 'end' ].
<br/>- [ Character home ] -> [ 'home' ].
<br/>- [ Character pageDown ] -> [ 'pageDown' ].
<br/>- [ Character pageUp ] -> [ 'pageUp' ].
<br/>-
<br/>- [ Character euro ] -> [ 'euro' ].
<br/>- [ Character insert ] -> [ 'insert' ].
<br/>-
<br/>- } otherwise: [ String with: kc ]).
<br/>
<br/> keyString size > 1 ifTrue: [ firstBracket value ].
<br/> aStream nextPutAll: keyString.
<br/>
<br/> inBrackets ifTrue: [aStream nextPut: $> ]!
<br/><br/>Item was changed:
<br/> ----- Method: KeyboardEvent>>printOn: (in category 'printing') -----
<br/> printOn: aStream
<br/> "Print the receiver on a stream"
<br/>
<br/> aStream nextPut: $[.
<br/> aStream nextPutAll: self cursorPoint printString; space.
<br/> aStream nextPutAll: type; space.
<br/>
<br/> self isKeystroke ifTrue: [
<br/> aStream nextPutAll: ''''.
<br/> self printKeyStringOn: aStream.
<br/>+ aStream nextPut: $'; space].
<br/>- aStream nextPut: $'; space.
<br/>- aStream nextPutAll: '['.
<br/>- self printPhysicalModifiersOn: aStream.
<br/>- aStream nextPutAll: '] '].
<br/>
<br/> aStream nextPut: $(.
<br/> aStream nextPutAll: keyValue printString.
<br/> aStream nextPut: $); space.
<br/>
<br/> aStream nextPutAll: timeStamp printString.
<br/> aStream nextPut: $]!
<br/><br/>Item was removed:
<br/>- ----- Method: KeyboardEvent>>printPhysicalModifiersOn: (in category 'printing') -----
<br/>- printPhysicalModifiersOn: aStream
<br/>- "Help users understand the physical modifier keys that where involved in this event."
<br/>-
<br/>- self labelsForPhysicalModifiers
<br/>- do: [:modifier | aStream nextPutAll: modifier]
<br/>- separatedBy: [aStream nextPutAll: ' + '].!
<br/><br/>Item was removed:
<br/>- ----- Method: KeyboardEvent>>scanCode: (in category 'private') -----
<br/>- scanCode: ignore
<br/>- " OB-Tests expects this "!
<br/><br/>Item was changed:
<br/> ----- Method: KeyboardEvent>>setType:buttons:position:keyValue:hand:stamp: (in category 'private') -----
<br/> setType: aSymbol buttons: anInteger position: pos keyValue: aValue hand: aHand stamp: stamp
<br/>+
<br/>+ self
<br/>+ setType: aSymbol
<br/>+ buttons: anInteger
<br/>+ position: pos
<br/>+ keyValue: aValue
<br/>+ keyCode: #unknown
<br/>+ hand: aHand
<br/>+ stamp: stamp.!
<br/>- type := aSymbol.
<br/>- buttons := anInteger.
<br/>- position := pos.
<br/>- keyValue := aValue.
<br/>- source := aHand.
<br/>- wasHandled := false.
<br/>- timeStamp := stamp.!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>setType:buttons:position:keyValue:keyCode:hand:stamp: (in category 'private') -----
<br/>+ setType: aSymbol buttons: anInteger position: pos keyValue: aValue keyCode: aCode hand: aHand stamp: stamp
<br/>+ type := aSymbol.
<br/>+ buttons := anInteger.
<br/>+ position := pos.
<br/>+ keyValue := aValue.
<br/>+ keyCode := aCode.
<br/>+ source := aHand.
<br/>+ wasHandled := false.
<br/>+ timeStamp := stamp.!
<br/><br/>Item was changed:
<br/> ----- Method: KeyboardEvent>>storeOn: (in category 'printing') -----
<br/> storeOn: aStream
<br/>
<br/> aStream nextPutAll: type.
<br/> aStream space.
<br/> self timeStamp storeOn: aStream.
<br/> aStream space.
<br/> buttons storeOn: aStream.
<br/> aStream space.
<br/> keyValue storeOn: aStream.
<br/>+ aStream space.
<br/>+ keyCode storeOn: aStream.
<br/> !
<br/><br/>Item was changed:
<br/> ----- Method: KeyboardEvent>>type:readFrom: (in category 'initialize') -----
<br/> type: eventType readFrom: aStream
<br/> type := eventType.
<br/> timeStamp := Integer readFrom: aStream.
<br/> aStream skip: 1.
<br/> buttons := Integer readFrom: aStream.
<br/> aStream skip: 1.
<br/>+ keyValue := Integer readFrom: aStream.
<br/>+ aStream skip: 1.
<br/>+ keyCode := Integer readFrom: aStream.!
<br/>- keyValue := Integer readFrom: aStream.!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>virtualKey (in category 'morphic/tools - accessing') -----
<br/>+ virtualKey
<br/>+
<br/>+ ^ self key!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardEvent>>virtualModifiers (in category 'morphic/tools - accessing') -----
<br/>+ virtualModifiers
<br/>+
<br/>+ ^ self modifiers!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardExerciser>>lastEvent (in category 'accessing') -----
<br/>+ lastEvent
<br/>+
<br/>+ | view event |
<br/>+ view := self submorphs last.
<br/>+ (view hasProperty: #event) ifFalse: [^ nil].
<br/>+ event := view valueOfProperty: #event.
<br/>+ event isCollection ifTrue: [event := event last].
<br/>+ ^ event!
<br/><br/>Item was changed:
<br/> ----- Method: KeyboardExerciser>>logEvent: (in category 'event handling') -----
<br/> logEvent: evt
<br/>
<br/> | eventMorph |
<br/>+ evt = self lastEvent
<br/>+ ifTrue: [^ self logEventRepetition: evt].
<br/>+
<br/> eventMorph := evt asMorph.
<br/> eventMorph
<br/> setProperty: #event toValue: evt copy;
<br/>+ balloonText: ('Click to inspect. Shift+click to explore.\\Virtual key: {7}\Virtual modifiers: {4}\\Physical key: {8}\Physical modifiers: {5}\\Key value: 0x{1} ({2}) \Key character: {3}\\{6}' withCRs format: {
<br/>- balloonText: ('Click to inspect. Shift+click to explore.\\Key value: 0x{1} ({2}) \Key character: {3}\Virtual modifiers: {4}\Physical modifiers: {5}\\{6}' withCRs format: {
<br/> evt keyValue printPaddedWith: $0 to: 2 base: 16.
<br/> evt keyValue.
<br/> evt isKeystroke ifTrue: [evt keyCharacter printString] ifFalse: ['-'].
<br/>+ (evt virtualModifiers joinSeparatedBy: ' ') asUppercase.
<br/>+ (evt physicalModifiers joinSeparatedBy: ' ') asUppercase.
<br/>+ evt printString.
<br/>+ evt virtualKey printString.
<br/>+ evt physicalKey asString printString}).
<br/>- evt modifierString.
<br/>- (evt labelsForPhysicalModifiers joinSeparatedBy: ' ') asUppercase.
<br/>- evt printString}).
<br/>
<br/> eventMorph
<br/> on: #mouseEnter send: #handleEvent:emphasize: to: self;
<br/> on: #mouseLeave send: #handleEvent:deemphasize: to: self;
<br/> on: #mouseDown send: #handleEvent:inspect: to: self.
<br/>
<br/> self addMorphBack: eventMorph.!
<br/><br/>Item was added:
<br/>+ ----- Method: KeyboardExerciser>>logEventRepetition: (in category 'event handling') -----
<br/>+ logEventRepetition: evt
<br/>+
<br/>+ | label lastEvents box |
<br/>+ (self submorphs last hasProperty: #repetition)
<br/>+ ifTrue: [box := self submorphs last. label := box submorphs first]
<br/>+ ifFalse: [
<br/>+ box := Morph new
<br/>+ setProperty: #repetition toValue: true;
<br/>+ color: Color transparent;
<br/>+ layoutPolicy: TableLayout new;
<br/>+ hResizing: #shrinkWrap;
<br/>+ vResizing:#shrinkWrap;
<br/>+ yourself.
<br/>+ label := '' asText asMorph lock.
<br/>+ box addMorph: label.
<br/>+ box setProperty: #event toValue: (OrderedCollection with: self lastEvent).
<br/>+ self addMorphBack: box].
<br/>+
<br/>+ lastEvents := box valueOfProperty: #event.
<br/>+ lastEvents add: evt copy.
<br/>+ box setProperty: #event toValue: lastEvents.
<br/>+
<br/>+ label newContents: (('x ', (lastEvents size)) asText
<br/>+ addAttribute: (TextFontReference toFont: Preferences standardButtonFont);
<br/>+ yourself).
<br/>+ box balloonText: ('{1}{2}' format: {
<br/>+ lastEvents size > 10 ifTrue: ['... ', (lastEvents size - 10), ' older events and:', String cr] ifFalse: [''].
<br/>+ (lastEvents last: (10 min: lastEvents size)) joinSeparatedBy: String cr.
<br/>+ }).
<br/>+
<br/>+ box
<br/>+ on: #mouseEnter send: #handleEvent:emphasize: to: self;
<br/>+ on: #mouseLeave send: #handleEvent:deemphasize: to: self;
<br/>+ on: #mouseDown send: #handleEvent:inspect: to: self.!
<br/><br/>Item was added:
<br/>+ ----- Method: UserInputEvent>>modifiers (in category 'accessing') -----
<br/>+ modifiers
<br/>+
<br/>+ ^ Array streamContents: [:s |
<br/>+ self controlKeyPressed ifTrue: [s nextPut: #ctrl].
<br/>+ self optionKeyPressed ifTrue:[s nextPut: #opt].
<br/>+ self commandKeyPressed ifTrue:[s nextPut: #cmd].
<br/>+ self shiftPressed ifTrue:[s nextPut: #shift]]!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130493
The Trunk: Kernel-mt.1403.mcz
2021-06-17T23:32:21Z
2021-06-17T23:32:21Z
commits-2
Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Kernel-mt.1403.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Kernel-mt.1403.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Kernel-mt.1403
<br/>Author: mt
<br/>Time: 18 June 2021, 8:32:18.330904 am
<br/>UUID: 896b2999-9c3e-4df2-985b-92adf7d228a4
<br/>Ancestors: Kernel-nice.1402
<br/><br/>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.
<br/><br/>See <a href="http://forum.world.st/Please-try-out-Cross-platform-mapping-for-virtual-key-codes-tp5129188.html" target="_top" rel="nofollow" link="external">http://forum.world.st/Please-try-out-Cross-platform-mapping-for-virtual-key-codes-tp5129188.html</a><br/><br/>=============== Diff against Kernel-nice.1402 ===============
<br/><br/>Item was changed:
<br/> Object subclass: #EventSensor
<br/> instanceVariableNames: 'mouseButtons mousePosition mouseWheelDelta keyboardBuffer interruptKey interruptSemaphore eventQueue inputSemaphore lastEventPoll hasInputSemaphore lastEventTime'
<br/>+ classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodePreferences KeyDecodeTable VirtualKeyTable'
<br/>- classVariableNames: 'ButtonDecodeTable EventPollPeriod EventTicklerProcess InterruptWatcherProcess KeyDecodePreferences KeyDecodeTable'
<br/> poolDictionaries: 'EventSensorConstants'
<br/> category: 'Kernel-Processes'!
<br/>
<br/> !EventSensor commentStamp: 'mt 12/13/2019 14:38' prior: 0!
<br/> An EventSensor is an interface to the user input devices.
<br/> There is at least one instance of EventSensor named Sensor in the system.
<br/>
<br/> 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.
<br/>
<br/> For platforms that support true asynchronous event notification, the semaphore will be signaled to indicate pending events.
<br/> On platforms that do not support asynchronous notifications about events, the UI will have to poll EventSensor periodically to read events from the VM.
<br/>
<br/> Instance variables:
<br/> mouseButtons <Integer> - mouse button state as replacement for primMouseButtons
<br/> mousePosition <Point> - mouse position as replacement for primMousePt
<br/> keyboardBuffer <SharedQueue> - keyboard input buffer
<br/> interruptKey <Integer> - currently defined interrupt key
<br/> interruptSemaphore <Semaphore> - the semaphore signaled when the interruptKey is detected
<br/> eventQueue <SharedQueue> - an optional event queue for event driven applications
<br/> inputSemaphore <Semaphore>- the semaphore signaled by the VM if asynchronous event notification is supported
<br/> lastEventPoll <Integer> - the last millisecondClockValue at which we called fetchMoreEvents
<br/> hasInputSemaphore <Boolean> - true if my inputSemaphore has actually been signaled at least once.
<br/>
<br/> Class variables:
<br/> ButtonDecodeTable <ByteArray> - maps mouse buttons as reported by the VM to ones reported in the events.
<br/> KeyDecodeTable <Dictionary<SmallInteger->SmallInteger>> - maps some keys and their modifiers to other keys (used for instance to map Ctrl-X to Alt-X)
<br/> InterruptSemaphore <Semaphore> - signalled by the the VM and/or the event loop upon receiving an interrupt keystroke.
<br/> InterruptWatcherProcess <Process> - waits on the InterruptSemaphore and then responds as appropriate.
<br/> EventPollPeriod <Integer> - the number of milliseconds to wait between polling for more events in the userInterruptHandler.
<br/> EventTicklerProcess <Process> - the process that makes sure that events are polled for often enough (at least every EventPollPeriod milliseconds).
<br/>
<br/> Event format:
<br/> 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.
<br/>
<br/> Currently, the following events are defined:
<br/>
<br/> Null event
<br/> =============
<br/> The Null event is returned when the ST side asks for more events but no more events are available.
<br/> Structure:
<br/> [1] - event type 0
<br/> [2-8] - unused
<br/>
<br/> Mouse event structure
<br/> ==========================
<br/> Mouse events are generated when mouse input is detected.
<br/> [1] - event type 1
<br/> [2] - time stamp
<br/> [3] - mouse x position
<br/> [4] - mouse y position
<br/> [5] - button state; bitfield with the following entries:
<br/> 1 - 2r001 yellow (e.g., right) button
<br/> 2 - 2r010 blue (e.g., middle) button
<br/> 4 - 2r100 red (e.g., left) button
<br/> [all other bits are currently undefined]
<br/> [6] - modifier keys; bitfield with the following entries:
<br/> 1 - shift key
<br/> 2 - ctrl key
<br/> 4 - (Mac specific) option key
<br/> 8 - Cmd/Alt key
<br/> [all other bits are currently undefined]
<br/> [7] - reserved.
<br/> [8] - host window id.
<br/>
<br/> Keyboard events
<br/> ====================
<br/> Keyboard events are generated when keyboard input is detected.
<br/> [1] - event type 2
<br/> [2] - time stamp
<br/> [3] - character code (Ascii)
<br/> For now the character code is in Mac Roman encoding. See #macToSqueak.
<br/> For key press/release (see [4]), character codes are normalized.
<br/> [4] - press state; integer with the following meaning
<br/> 0 - character (aka. key stroke or key still pressed)
<br/> 1 - key press (aka. key down)
<br/> 2 - key release (aka. key up)
<br/> [5] - modifier keys (same as in mouse events)
<br/> For key press/release (see [4]), modifier keys are still accessible.
<br/> [6] - character code (Unicode UTF32)
<br/> Manual decoding via KeyboardInputInterpreter possible.
<br/> For key press/release (see [4]), character codes are normalized.
<br/> [7] - reserved.
<br/> [8] - host window id.
<br/>
<br/> Mouse-wheel event structure
<br/> ==========================
<br/> Mouse-wheel events are generated when mouse-wheel input is detected.
<br/> [1] - event type 7
<br/> [2] - time stamp
<br/> [3] - horizontal scroll delta
<br/> [4] - vertical scroll delta
<br/> [5] - button state (same as in mouse events)
<br/> [6] - modifier keys (same as in mouse events)
<br/> [7] - reserved.
<br/> [8] - host window id.
<br/> !
<br/><br/>Item was changed:
<br/> ----- Method: EventSensor class>>initialize (in category 'class initialization') -----
<br/> initialize
<br/>
<br/> Smalltalk addToStartUpList: self before: ProcessorScheduler.
<br/> Smalltalk addToShutDownList: self.
<br/>
<br/> KeyDecodePreferences := Dictionary new.
<br/>
<br/> self installKeyDecodeTable.
<br/>+ self installMouseDecodeTable.
<br/>+ self installVirtualKeyTable.!
<br/>- self installMouseDecodeTable.!
<br/><br/>Item was changed:
<br/> ----- Method: EventSensor class>>installMappingToPrintableCharacters (in category 'key decode table') -----
<br/> installMappingToPrintableCharacters
<br/> "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."
<br/>
<br/> 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."
<br/>
<br/>+ 1 "SOH" to: 27 "ESC" do: [:control |
<br/>+ #(2r0010 "ctrl" 2r0110 "ctrl+opt" 2r1010 "ctrl+cmd" 2r1110 "ctrl+opt+cmd")
<br/>+ do: [:modifiers | "Note that only macOS needs those other combinations."
<br/>+ KeyDecodeTable
<br/>+ at: { control . modifiers }
<br/>+ put: { control bitOr: 16r60 "+96" . modifiers }].
<br/>+ #(2r0011 "shift+ctrl" 2r0111 "shift+ctrl+opt" 2r1011 "shift+ctrl+cmd" 2r1111 "shift+ctrl+opt+cmd")
<br/>+ do: [:modifiers | "Note that only macOS needs those other combinations."
<br/>+ KeyDecodeTable
<br/>+ at: { control . modifiers }
<br/>+ put: { control bitOr: 16r40 "+64" . modifiers }]].
<br/>+
<br/>+ 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."
<br/>+ KeyDecodeTable
<br/>+ at: { 0 "NUL" . 2r0010 "ctrl" }
<br/>+ put: { 32 "SPACE". 2 "ctrl" }.
<br/>+ KeyDecodeTable
<br/>+ at: { 0 "NUL" . 2r0011 "ctrl+shift" }
<br/>+ put: { 32 "SPACE". 2r0011 "ctrl+shift" }.!
<br/>- 0 "NUL" to: 27 "ESC" do: [:control |
<br/>- KeyDecodeTable
<br/>- at: { control . 2r0010 "ctrl" }
<br/>- put: { control bitOr: 16r60 "+96" . 2 "ctrl" }.
<br/>- KeyDecodeTable
<br/>- at: { control . 2r0011 "ctrl+shift" }
<br/>- put: { control bitOr: 16r40 "+64" . 2r0011 "ctrl+shift" }].!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>installVirtualKeyTable (in category 'class initialization') -----
<br/>+ installVirtualKeyTable
<br/>+
<br/>+ VirtualKeyTable := Dictionary newFrom: (
<br/>+ Smalltalk windowSystemName
<br/>+ caseOf: {
<br/>+ ['Windows'] -> [self virtualKeysOnWindows].
<br/>+ ['Win32' "older VMs"] -> [self virtualKeysOnWindows].
<br/>+ ['Aqua'] -> [self virtualKeysOnMacOS].
<br/>+ ['X11'] -> [self virtualKeysOnX11].
<br/>+ ['RiscOS'] -> [{}].
<br/>+ ['Quartz'] -> [{}].
<br/>+ } otherwise: [{}]).
<br/>+
<br/>+ "Shift 8 bits to not overwrite virtual-key mappings from above."
<br/>+ self mapControlKeysToCommandKeys ifTrue: [
<br/>+ VirtualKeyTable
<br/>+ at: (2r0010 "ctrl" bitShift: 8)
<br/>+ put: (2r1010 "cmd+ctrl").
<br/>+ VirtualKeyTable
<br/>+ at: (2r0011 "ctrl+shift" bitShift: 8)
<br/>+ put: (2r1011 "cmd+ctrl+shift")].
<br/>+
<br/>+ self mapAltKeysToOptionKeys ifTrue: [
<br/>+ VirtualKeyTable
<br/>+ at: (2r1000 "cmd/alt" bitShift: 8)
<br/>+ put: (2r1100 "cmd/alt+opt").
<br/>+ VirtualKeyTable
<br/>+ at: (2r1001 "cmd/alt+shift" bitShift: 8)
<br/>+ put: (2r1101 "cmd/alt+opt+shift")].!
<br/><br/>Item was changed:
<br/> ----- Method: EventSensor class>>mapAltKeysToOptionKeys: (in category 'preferences') -----
<br/> mapAltKeysToOptionKeys: aBooleanOrNil
<br/>
<br/> aBooleanOrNil = self mapAltKeysToOptionKeys
<br/> ifTrue: [^ self].
<br/>
<br/> aBooleanOrNil
<br/> ifNil: [
<br/> KeyDecodePreferences
<br/> removeKey: #mapAltKeysToOptionKeys]
<br/> ifNotNil: [
<br/> KeyDecodePreferences
<br/> at: #mapAltKeysToOptionKeys
<br/> put: aBooleanOrNil].
<br/>
<br/>+ self installKeyDecodeTable.
<br/>+ self installVirtualKeyTable.!
<br/>- self installKeyDecodeTable.!
<br/><br/>Item was changed:
<br/> ----- Method: EventSensor class>>mapControlKeysToCommandKeys: (in category 'preferences') -----
<br/> mapControlKeysToCommandKeys: aBooleanOrNil
<br/>
<br/> aBooleanOrNil
<br/> ifNil: [
<br/> KeyDecodePreferences
<br/> removeKey: #mapControlKeysToCommandKeys]
<br/> ifNotNil: [
<br/> KeyDecodePreferences
<br/> at: #mapControlKeysToCommandKeys
<br/> put: aBooleanOrNil].
<br/>
<br/>+ self installKeyDecodeTable.
<br/>+ self installVirtualKeyTable.!
<br/>- self installKeyDecodeTable.!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>simplifyVirtualKeyCodes (in category 'preferences') -----
<br/>+ simplifyVirtualKeyCodes
<br/>+ <preference: 'Simplify virtual-key codes'
<br/>+ categoryList: #(keyboard events input)
<br/>+ 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.'
<br/>+ type: #Boolean>
<br/>+
<br/>+ ^ KeyDecodePreferences
<br/>+ at: #simplifyVirtualKeyCodes
<br/>+ ifAbsent: [true]!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>simplifyVirtualKeyCodes: (in category 'preferences') -----
<br/>+ simplifyVirtualKeyCodes: aBooleanOrNil
<br/>+
<br/>+ aBooleanOrNil = self simplifyVirtualKeyCodes
<br/>+ ifTrue: [^ self].
<br/>+
<br/>+ aBooleanOrNil
<br/>+ ifNil: [
<br/>+ KeyDecodePreferences
<br/>+ removeKey: #simplifyVirtualKeyCodes]
<br/>+ ifNotNil: [
<br/>+ KeyDecodePreferences
<br/>+ at: #simplifyVirtualKeyCodes
<br/>+ put: aBooleanOrNil].
<br/>+
<br/>+ self installVirtualKeyTable.!
<br/><br/>Item was removed:
<br/>- ----- Method: EventSensor class>>startUp (in category 'system startup') -----
<br/>- startUp
<br/>-
<br/>- Smalltalk platformName = 'Mac OS'
<br/>- ifTrue: [
<br/>- self mapAltKeysToOptionKeys: false.
<br/>- self mapControlKeysToCommandKeys: false]
<br/>- ifFalse: [
<br/>- self mapAltKeysToOptionKeys: true.
<br/>- self mapControlKeysToCommandKeys: true].
<br/>-
<br/>- self default startUp.!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>startUp: (in category 'system startup') -----
<br/>+ startUp: resuming
<br/>+
<br/>+ resuming ifTrue: [
<br/>+ Smalltalk platformName = 'Mac OS'
<br/>+ ifTrue: [
<br/>+ self mapAltKeysToOptionKeys: false.
<br/>+ self mapControlKeysToCommandKeys: false]
<br/>+ ifFalse: [
<br/>+ self mapAltKeysToOptionKeys: true.
<br/>+ self mapControlKeysToCommandKeys: true].
<br/>+ self installVirtualKeyTable ].
<br/>+
<br/>+ self default startUp.!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>virtualKeyAt: (in category 'virtual keys') -----
<br/>+ virtualKeyAt: keyCode
<br/>+ "Answers a representation for the (non-modifier) key, which should be consistent across platforms considering its cause."
<br/>+
<br/>+ ^ self virtualKeyTable at: keyCode!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>virtualKeyTable (in category 'virtual keys') -----
<br/>+ virtualKeyTable
<br/>+
<br/>+ ^ VirtualKeyTable ifNil: [self installVirtualKeyTable]!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>virtualKeysOnMacOS (in category 'virtual keys') -----
<br/>+ virtualKeysOnMacOS
<br/>+ "Based on Carbon's Events.h -- <a href="https://snipplr.com/view/42797" target="_top" rel="nofollow" link="external">https://snipplr.com/view/42797</a>"
<br/>+
<br/>+ ^ {
<br/>+ 16r00 -> $A. "#'kVK_ANSI_A'"
<br/>+ 16r01 -> $S. "#'kVK_ANSI_S'"
<br/>+ 16r02 -> $D. "#'kVK_ANSI_D'"
<br/>+ 16r03 -> $F. "#'kVK_ANSI_F'"
<br/>+ 16r04 -> $H. "#'kVK_ANSI_H'"
<br/>+ 16r05 -> $G. "#'kVK_ANSI_G'"
<br/>+ 16r06 -> $Z. "#'kVK_ANSI_Z'"
<br/>+ 16r07 -> $X. "#'kVK_ANSI_X'"
<br/>+ 16r08 -> $C. "#'kVK_ANSI_C'"
<br/>+ 16r09 -> $V. "#'kVK_ANSI_V'"
<br/>+ 16r0B -> $B. "#'kVK_ANSI_B'"
<br/>+ 16r0C -> $Q. "#'kVK_ANSI_Q'"
<br/>+ 16r0D -> $W. "#'kVK_ANSI_W'"
<br/>+ 16r0E -> $E. "#'kVK_ANSI_E'"
<br/>+ 16r0F -> $R. "#'kVK_ANSI_R'"
<br/>+ 16r10 -> $Y. "#'kVK_ANSI_Y'"
<br/>+ 16r11 -> $T. "#'kVK_ANSI_T'"
<br/>+ 16r12 -> $1. "#'kVK_ANSI_1'"
<br/>+ 16r13 -> $2. "#'kVK_ANSI_2'"
<br/>+ 16r14 -> $3. "#'kVK_ANSI_3'"
<br/>+ 16r15 -> $4. "#'kVK_ANSI_4'"
<br/>+ 16r16 -> $6. "#'kVK_ANSI_6'"
<br/>+ 16r17 -> $5. "#'kVK_ANSI_5'"
<br/>+ 16r18 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'kVK_ANSI_Equal']).
<br/>+ 16r19 -> $9. "#'kVK_ANSI_9'"
<br/>+ 16r1A -> $7. "#'kVK_ANSI_7'"
<br/>+ 16r1B -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Minus']).
<br/>+ 16r1C -> $8. "#'kVK_ANSI_8'"
<br/>+ 16r1D -> $0. "#'kVK_ANSI_0'"
<br/>+ 16r1E -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'kVK_ANSI_RightBracket']).
<br/>+ 16r1F -> $O. "#'kVK_ANSI_O'"
<br/>+ 16r20 -> $U. "#'kVK_ANSI_U'"
<br/>+ 16r21 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_LeftBracket']).
<br/>+ 16r22 -> $I. "#'kVK_ANSI_I'"
<br/>+ 16r23 -> $P. "#'kVK_ANSI_P'"
<br/>+ 16r25 -> $L. "#'kVK_ANSI_L'"
<br/>+ 16r26 -> $J. "#'kVK_ANSI_J'"
<br/>+ 16r27 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak3] ifFalse: [#'kVK_ANSI_Quote']).
<br/>+ 16r28 -> $K. "#'kVK_ANSI_K'"
<br/>+ 16r29 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Semicolon']).
<br/>+ 16r2A -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Backslash']).
<br/>+ 16r2B -> #squeakComma. "#'kVK_ANSI_Comma'"
<br/>+ 16r2C -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ANSI_Slash']).
<br/>+ 16r2D -> $N. "#'kVK_ANSI_N'"
<br/>+ 16r2E -> $M. "#'kVK_ANSI_M'"
<br/>+ 16r2F -> #squeakPeriod. "#'kVK_ANSI_Period'"
<br/>+ 16r32 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak4] ifFalse: [#'kVK_ANSI_Grave']).
<br/>+ 16r41 -> #numDec. "#'kVK_ANSI_KeypadDecimal'"
<br/>+ 16r43 -> #numMul. "#'kVK_ANSI_KeypadMultiply'"
<br/>+ 16r45 -> #numAdd. "#'kVK_ANSI_KeypadPlus'"
<br/>+ 16r47 -> #numClr. "#'kVK_ANSI_KeypadClear'"
<br/>+ 16r4B -> #numDiv. "#'kVK_ANSI_KeypadDivide'"
<br/>+ 16r4C -> (self simplifyVirtualKeyCodes ifTrue: [Character return] ifFalse: [Character enter]). "#'kVK_ANSI_KeypadEnter'"
<br/>+ 16r4E -> #numSub. "#'kVK_ANSI_KeypadMinus'"
<br/>+ 16r51 -> #numEqu. "#'kVK_ANSI_KeypadEquals'"
<br/>+ 16r52 -> #num0. "#'kVK_ANSI_Keypad0'"
<br/>+ 16r53 -> #num1. "#'kVK_ANSI_Keypad1'"
<br/>+ 16r54 -> #num2. "#'kVK_ANSI_Keypad2'"
<br/>+ 16r55 -> #num3. "#'kVK_ANSI_Keypad3'"
<br/>+ 16r56 -> #num4. "#'kVK_ANSI_Keypad4'"
<br/>+ 16r57 -> #num5. "#'kVK_ANSI_Keypad5'"
<br/>+ 16r58 -> #num6. "#'kVK_ANSI_Keypad6'"
<br/>+ 16r59 -> #num7. "#'kVK_ANSI_Keypad7'"
<br/>+ 16r5B -> #num8. "#'kVK_ANSI_Keypad8'"
<br/>+ 16r5C -> #num9. "#'kVK_ANSI_Keypad9'"
<br/>+ 16r24 -> Character return. "#'kVK_Return'"
<br/>+ 16r30 -> Character tab. "#'kVK_Tab'"
<br/>+ 16r31 -> Character space. "#'kVK_Space'"
<br/>+ 16r33 -> Character backspace. "#'kVK_Delete'"
<br/>+ 16r35 -> Character escape. "#'kVK_Escape'"
<br/>+ 16r36 -> #command. "#'kVK_RightCommand'"
<br/>+ 16r37 -> #command. "#'kVK_Command'"
<br/>+ 16r38 -> #shift. "#'kVK_Shift'"
<br/>+ 16r39 -> #capsLock. "#'kVK_CapsLock'"
<br/>+ 16r3A -> #option. "#'kVK_Option'"
<br/>+ 16r3B -> #control. "#'kVK_Control'"
<br/>+ 16r3C -> #shift. "#'kVK_RightShift'"
<br/>+ 16r3D -> #option. "#'kVK_RightOption'"
<br/>+ 16r3E -> #control. "#'kVK_RightControl'"
<br/>+ 16r3F -> #'kVK_Function'.
<br/>+ 16r40 -> #F17. "#'kVK_F17'"
<br/>+ 16r48 -> #'kVK_VolumeUp'.
<br/>+ 16r49 -> #'kVK_VolumeDown'.
<br/>+ 16r4A -> #'kVK_Mute'.
<br/>+ 16r4F -> #F18. "#'kVK_F18'"
<br/>+ 16r50 -> #F19. "#'kVK_F19'"
<br/>+ 16r5A -> #F20. "#'kVK_F20'"
<br/>+ 16r60 -> #F5. "#'kVK_F5'"
<br/>+ 16r61 -> #F6. "#'kVK_F6'"
<br/>+ 16r62 -> #F7. "#'kVK_F7'"
<br/>+ 16r63 -> #F3. "#'kVK_F3'"
<br/>+ 16r64 -> #F8. "#'kVK_F8'"
<br/>+ 16r65 -> #F9. "#'kVK_F9'"
<br/>+ 16r67 -> #F11. "#'kVK_F11'"
<br/>+ 16r69 -> #F13. "#'kVK_F13'"
<br/>+ 16r6A -> #F16. "#'kVK_F16'"
<br/>+ 16r6B -> #F14. "#'kVK_F14'"
<br/>+ 16r6D -> #F10. "#'kVK_F10'"
<br/>+ 16r6F -> #F12. "#'kVK_F12'"
<br/>+ 16r71 -> #F15. "#'kVK_F15'"
<br/>+ 16r72 -> #help. "#'kVK_Help'"
<br/>+ 16r73 -> Character home. "#'kVK_Home'"
<br/>+ 16r74 -> Character pageUp. "#'kVK_PageUp'"
<br/>+ 16r75 -> Character delete. "#'kVK_ForwardDelete'"
<br/>+ 16r76 -> #F4. "#'kVK_F4'"
<br/>+ 16r77 -> Character end. "#'kVK_End'"
<br/>+ 16r78 -> #F2. "#'kVK_F2'"
<br/>+ 16r79 -> Character pageDown. "#'kVK_PageDown'"
<br/>+ 16r7A -> #F1. "#'kVK_F1'"
<br/>+ 16r7B -> Character arrowLeft. "#'kVK_LeftArrow'"
<br/>+ 16r7C -> Character arrowRight. "#'kVK_RightArrow'"
<br/>+ 16r7D -> Character arrowDown. "#'kVK_DownArrow'"
<br/>+ 16r7E -> Character arrowUp. "#'kVK_UpArrow'"
<br/>+ 16r0A -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'kVK_ISO_Section']).
<br/>+ 16r5D -> #'kVK_JIS_Yen'.
<br/>+ 16r5E -> #'kVK_JIS_Underscore'.
<br/>+ 16r5F -> #'kVK_JIS_KeypadComma'.
<br/>+ 16r66 -> #'kVK_JIS_Eisu'.
<br/>+ 16r68 -> #'kVK_JIS_Kana'.
<br/>+ }!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>virtualKeysOnWindows (in category 'virtual keys') -----
<br/>+ virtualKeysOnWindows
<br/>+ "<a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes" target="_top" rel="nofollow" link="external">https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes</a><br/>+
<br/>+ Tweaked to Windows 10 Version 20H2 (Build 19042.928)
<br/>+ Microsoft Surface Pro 6 (GERMAN)"
<br/>+
<br/>+ ^ {
<br/>+
<br/>+ 16r01 -> Character home. "#'VK_HOME'" "Overshadows #'VK_LBUTTON' --- Left mouse button"
<br/>+ 16r02 -> #'VK_RBUTTON'. "Right mouse button"
<br/>+ 16r03 -> #'VK_CANCEL'. "Control-break processing"
<br/>+ 16r04 -> Character end. "#'VK_END'" "Overshadows #'VK_MBUTTON' --- Middle mouse button"
<br/>+ 16r05 -> Character insert. "#'VK_INSERT'" "Overshadows #'VK_XBUTTON1' --- X1 mouse button"
<br/>+ 16r06 -> #'VK_XBUTTON2'. "X2 mouse button"
<br/>+ 16r07 -> nil.
<br/>+ 16r08 -> Character backspace. "#'VK_BACK'"
<br/>+ 16r09 -> Character tab. "#'VK_TAB'"
<br/>+ 16r0A -> nil.
<br/>+ 16r0B -> Character pageUp. "#'VK_PRIOR'" "PAGE UP key"
<br/>+ 16r0C -> Character pageDown. "#'VK_NEXT'" "PAGE DOWN key --- overshadows #'VK_CLEAR'"
<br/>+ 16r0D -> Character return. "#'VK_RETURN'" "ENTER key"
<br/>+ 16r0E -> nil.
<br/>+ 16r0F -> nil.
<br/>+ 16r10 -> #shift. "#'VK_SHIFT'"
<br/>+ 16r11 -> (self mapControlKeysToCommandKeys ifTrue: [#command] ifFalse: [#control]). "#'VK_CONTROL'"
<br/>+ 16r12 -> (self mapAltKeysToOptionKeys ifTrue: [#option] ifFalse: [#command "aka. #alt"]). "#'VK_MENU'"
<br/>+ 16r13 -> #'VK_PAUSE'.
<br/>+ 16r14 -> #capsLock. "#'VK_CAPITAL'"
<br/>+ 16r15 -> #'VK_KANA'. "IME Kana/Hangul mode"
<br/>+ 16r16 -> #'VK_IME_ON'. "IME on"
<br/>+ 16r17 -> #'VK_JUNJA'. "IMA Junja mode"
<br/>+ 16r18 -> #'VK_FINAL'. "IME final mode"
<br/>+ 16r19 -> #'VK_KANJI'. "IME Kanji/Hanja mode"
<br/>+ 16r1A -> #'VK_IME_OFF'. "IME off"
<br/>+ 16r1B -> Character escape. "#'VK_ESCAPE'"
<br/>+ 16r1C -> Character arrowLeft. "#'VK_LEFT'" "LEFT ARROW. Overshadows #'VK_CONVERT' --- IME convert"
<br/>+ 16r1D -> Character arrowRight. "#'VK_RIGHT'" "RIGHT ARROW. Overshadows 'VK_NONCONVERT' --- IME nonconvert"
<br/>+ 16r1E -> Character arrowUp. "#'VK_UP'" "UP ARROW. Overshadows #'VK_ACCEPT' --- IME accept"
<br/>+ 16r1F -> Character arrowDown. "#'VK_DOWN'" "DOWN ARROW. Overshadows #'VK_MODECHANGE' --- IME mode change request"
<br/>+ 16r20 -> Character space. "#'VK_SPACE'" "SPACEBAR"
<br/>+ 16r21 -> #'VK_PRIOR'. "PAGE UP key. Not needed. See 16r0B"
<br/>+ 16r22 -> #'VK_NEXT'. "PAGE DOWN key. Not needed. See 16r0C"
<br/>+ 16r23 -> #'VK_END'. "Not needed. See 16r04"
<br/>+ 16r24 -> #'VK_HOME'. "Not needed. See 16r01"
<br/>+ 16r25 -> #'VK_LEFT'. "LEFT ARROW. Not needed. See 16r1C"
<br/>+ 16r26 -> #'VK_UP'. "UP ARROW. Not needed. See 16r1E"
<br/>+ 16r27 -> #'VK_RIGHT'. "RIGHT ARROW. Not needed. See 16r1D"
<br/>+ 16r28 -> #'VK_DOWN'. "DOWN ARROW. Not needed. See 16r1F"
<br/>+ 16r29 -> #'VK_SELECT'.
<br/>+ 16r2A -> #'VK_PRINT'.
<br/>+ 16r2B -> #'VK_EXECUTE'.
<br/>+ 16r2C -> #'VK_SNAPSHOT'. "PRINT SCREEN key"
<br/>+ 16r2D -> #'VK_INSERT'. "Not needed. See 16r05"
<br/>+ 16r2E -> #F16. "#'VK_F16' swapped with #'VK_DELETE'. See 16r7F"
<br/>+ 16r2F -> #help. "#'VK_HELP'"
<br/>+ 16r30 -> $0.
<br/>+ 16r31 -> $1.
<br/>+ 16r32 -> $2.
<br/>+ 16r33 -> $3.
<br/>+ 16r34 -> $4.
<br/>+ 16r35 -> $5.
<br/>+ 16r36 -> $6.
<br/>+ 16r37 -> $7.
<br/>+ 16r38 -> $8.
<br/>+ 16r39 -> $9.
<br/>+ 16r3A -> nil.
<br/>+ 16r3B -> nil.
<br/>+ 16r3C -> nil.
<br/>+ 16r3D -> nil.
<br/>+ 16r3E -> nil.
<br/>+ 16r3F -> nil.
<br/>+ 16r40 -> nil.
<br/>+ 16r41 -> $A.
<br/>+ 16r42 -> $B.
<br/>+ 16r43 -> $C.
<br/>+ 16r44 -> $D.
<br/>+ 16r45 -> $E.
<br/>+ 16r46 -> $F.
<br/>+ 16r47 -> $G.
<br/>+ 16r48 -> $H.
<br/>+ 16r49 -> $I.
<br/>+ 16r4A -> $J.
<br/>+ 16r4B -> $K.
<br/>+ 16r4C -> $L.
<br/>+ 16r4D -> $M.
<br/>+ 16r4E -> $N.
<br/>+ 16r4F -> $O.
<br/>+ 16r50 -> $P.
<br/>+ 16r51 -> $Q.
<br/>+ 16r52 -> $R.
<br/>+ 16r53 -> $S.
<br/>+ 16r54 -> $T.
<br/>+ 16r55 -> $U.
<br/>+ 16r56 -> $V.
<br/>+ 16r57 -> $W.
<br/>+ 16r58 -> $X.
<br/>+ 16r59 -> $Y.
<br/>+ 16r5A -> $Z.
<br/>+ 16r5B -> #'VK_LWIN'. "Left Windows key"
<br/>+ 16r5C -> #'VK_RWIN'. "Right windows key"
<br/>+ 16r5D -> #'VK_APPS'. "Applications key"
<br/>+ 16r5E -> nil.
<br/>+ 16r5F -> #'VK_SLEEP'. "Computer Sleep Key"
<br/>+ 16r60 -> #num0. "#'VK_NUMPAD0'"
<br/>+ 16r61 -> #num1. "#'VK_NUMPAD1'"
<br/>+ 16r62 -> #num2. "#'VK_NUMPAD2'"
<br/>+ 16r63 -> #num3. "#'VK_NUMPAD3'"
<br/>+ 16r64 -> #num4. "#'VK_NUMPAD4'"
<br/>+ 16r65 -> #num5. "#'VK_NUMPAD5'"
<br/>+ 16r66 -> #num6. "#'VK_NUMPAD6'"
<br/>+ 16r67 -> #num7. "#'VK_NUMPAD7'"
<br/>+ 16r68 -> #num8. "#'VK_NUMPAD8'"
<br/>+ 16r69 -> #num9. "#'VK_NUMPAD9'"
<br/>+ 16r6A -> #numMul. "#'VK_MULTIPLY'"
<br/>+ 16r6B -> #numAdd. "#'VK_ADD'"
<br/>+ 16r6C -> #'VK_SEPARATOR'.
<br/>+ 16r6D -> #numSub. "#'VK_SUBTRACT'"
<br/>+ 16r6E -> #numDec. "#'VK_DECIMAL'"
<br/>+ 16r6F -> #numDiv. "#'VK_DIVIDE'"
<br/>+ 16r70 -> #F1. "#'VK_F1'"
<br/>+ 16r71 -> #F2. "#'VK_F2'"
<br/>+ 16r72 -> #F3. "#'VK_F3'"
<br/>+ 16r73 -> #F4. "#'VK_F4'"
<br/>+ 16r74 -> #F5. "#'VK_F5'"
<br/>+ 16r75 -> #F6. "#'VK_F6'"
<br/>+ 16r76 -> #F7. "#'VK_F7'"
<br/>+ 16r77 -> #F8. "#'VK_F8'"
<br/>+ 16r78 -> #F9. "#'VK_F9'"
<br/>+ 16r79 -> #F10. "#'VK_F10'"
<br/>+ 16r7A -> #F11. "#'VK_F11'"
<br/>+ 16r7B -> #F12. "#'VK_F12'"
<br/>+ 16r7C -> #F13. "#'VK_F13'"
<br/>+ 16r7D -> #F14. "#'VK_F14'"
<br/>+ 16r7E -> #F15. "#'VK_F15'"
<br/>+ 16r7F -> Character delete. "#'VK_DELETE' swapped with #'VK_F16'. See 16r2E"
<br/>+ 16r80 -> #F17. "#'VK_F17'"
<br/>+ 16r81 -> #F18. "#'VK_F18'"
<br/>+ 16r82 -> #F19. "#'VK_F19'"
<br/>+ 16r83 -> #F20. "#'VK_F20'"
<br/>+ 16r84 -> #F21. "#'VK_F21'"
<br/>+ 16r85 -> #F22. "#'VK_F22'"
<br/>+ 16r86 -> #F23. "#'VK_F23'"
<br/>+ 16r87 -> #F24. "#'VK_F24'"
<br/>+ 16r88 -> nil.
<br/>+ 16r89 -> nil.
<br/>+ 16r8A -> nil.
<br/>+ 16r8B -> nil.
<br/>+ 16r8C -> nil.
<br/>+ 16r8D -> nil.
<br/>+ 16r8E -> nil.
<br/>+ 16r8F -> nil.
<br/>+ 16r90 -> #'VK_NUMLOCK'.
<br/>+ 16r91 -> #'VK_SCROLL'.
<br/>+ 16r92 -> nil.
<br/>+ 16r93 -> nil.
<br/>+ 16r94 -> nil.
<br/>+ 16r95 -> nil.
<br/>+ 16r96 -> nil.
<br/>+ 16r97 -> nil.
<br/>+ 16r98 -> nil.
<br/>+ 16r99 -> nil.
<br/>+ 16r9A -> nil.
<br/>+ 16r9B -> nil.
<br/>+ 16r9C -> nil.
<br/>+ 16r9D -> nil.
<br/>+ 16r9E -> nil.
<br/>+ 16r9F -> nil.
<br/>+ 16rA0 -> #'VK_LSHIFT'.
<br/>+ 16rA1 -> #'VK_RSHIFT'.
<br/>+ 16rA2 -> #'VK_LCONTROL'.
<br/>+ 16rA3 -> #'VK_RCONTROL'.
<br/>+ 16rA4 -> #'VK_LMENU'.
<br/>+ 16rA5 -> #'VK_RMENU'.
<br/>+ 16rA6 -> #'VK_BROWSER_BACK'.
<br/>+ 16rA7 -> #'VK_BROWSER_FORWARD'.
<br/>+ 16rA8 -> #'VK_BROWSER_REFRESH'.
<br/>+ 16rA9 -> #'VK_BROWSER_STOP'.
<br/>+ 16rAA -> #'VK_BROWSER_SEARCH'.
<br/>+ 16rAB -> #'VK_BROWSER_FAVORITES'.
<br/>+ 16rAC -> #'VK_BROWSER_HOME'.
<br/>+ 16rAD -> #'VK_VOLUME_MUTE'.
<br/>+ 16rAE -> #'VK_VOLUME_DOWN'.
<br/>+ 16rAF -> #'VK_VOLUME_UP'.
<br/>+ 16rB0 -> #'VK_MEDIA_NEXT_TRACK'.
<br/>+ 16rB1 -> #'VK_MEDIA_PREV_TRACK'.
<br/>+ 16rB2 -> #'VK_MEDIA_STOP'.
<br/>+ 16rB3 -> #'VK_MEDIA_PLAY_PAUSE'.
<br/>+ 16rB4 -> #'VK_LAUNCH_MAIL'.
<br/>+ 16rB5 -> #'VK_LAUNCH_MEDIA_SELECT'.
<br/>+ 16rB6 -> #'VK_LAUNCH_APP1'.
<br/>+ 16rB7 -> #'VK_LAUNCH_APP2'.
<br/>+ 16rB8 -> nil.
<br/>+ 16rB9 -> nil.
<br/>+
<br/>+ 16rBA -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_1']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ;: key"
<br/>+
<br/>+ 16rBB -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'VK_OEM_PLUS']).
<br/>+ "For any country/region, the + key -- mt. Haha. You wish."
<br/>+
<br/>+ 16rBC -> #squeakComma. "#'VK_OEM_COMMA'" "For any country/region, the , key"
<br/>+
<br/>+ 16rBD -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_MINUS']).
<br/>+ "For any country/region, the - key"
<br/>+
<br/>+ 16rBE -> #squeakPeriod. "#'VK_OEM_PERIOD'" "For any country/region, the . key"
<br/>+
<br/>+ 16rBF -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_2']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the /? key"
<br/>+
<br/>+ 16rC0 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_3']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the `~ key'"
<br/>+
<br/>+ 16rC1 -> nil.
<br/>+ 16rC2 -> nil.
<br/>+ 16rC3 -> nil.
<br/>+ 16rC4 -> nil.
<br/>+ 16rC5 -> nil.
<br/>+ 16rC6 -> nil.
<br/>+ 16rC7 -> nil.
<br/>+ 16rC8 -> nil.
<br/>+ 16rC9 -> nil.
<br/>+ 16rCA -> nil.
<br/>+ 16rCB -> nil.
<br/>+ 16rCC -> nil.
<br/>+ 16rCD -> nil.
<br/>+ 16rCE -> nil.
<br/>+ 16rCF -> nil.
<br/>+ 16rD0 -> nil.
<br/>+ 16rD1 -> nil.
<br/>+ 16rD2 -> nil.
<br/>+ 16rD3 -> nil.
<br/>+ 16rD4 -> nil.
<br/>+ 16rD5 -> nil.
<br/>+ 16rD6 -> nil.
<br/>+ 16rD7 -> nil.
<br/>+ 16rD8 -> nil.
<br/>+ 16rD9 -> nil.
<br/>+ 16rDA -> nil.
<br/>+
<br/>+ 16rDB -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_4']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the [{ key"
<br/>+
<br/>+ 16rDC -> (self simplifyVirtualKeyCodes ifTrue: [#squeak1] ifFalse: [#'VK_OEM_5']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the \| key"
<br/>+
<br/>+ 16rDD -> (self simplifyVirtualKeyCodes ifTrue: [#squeak2] ifFalse: [#'VK_OEM_6']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ]} key"
<br/>+
<br/>+ 16rDE -> (self simplifyVirtualKeyCodes ifTrue: [#squeak3] ifFalse: [#'VK_OEM_7']).
<br/>+ "Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the single-quote/double-quote key"
<br/>+
<br/>+ 16rDF -> #'VK_OEM_8'.
<br/>+ "Used for miscellaneous characters; it can vary by keyboard."
<br/>+
<br/>+ 16rE0 -> nil.
<br/>+ 16rE1 -> nil.
<br/>+
<br/>+ 16rE2 -> (self simplifyVirtualKeyCodes ifTrue: [#squeak4] ifFalse: [#'VK_OEM_102']).
<br/>+ "Either the angle bracket key or the backslash key on the RT 102-key keyboard"
<br/>+
<br/>+ 16rE3 -> nil.
<br/>+ 16rE4 -> nil.
<br/>+ 16rE5 -> #'VK_PROCESSKEY'. "IME PROCESS key"
<br/>+ 16rE6 -> nil.
<br/>+ 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."
<br/>+ 16rE8 -> nil.
<br/>+ 16rE9 -> nil.
<br/>+ 16rEA -> nil.
<br/>+ 16rEB -> nil.
<br/>+ 16rEC -> nil.
<br/>+ 16rED -> nil.
<br/>+ 16rEE -> nil.
<br/>+ 16rEF -> nil.
<br/>+ 16rF0 -> nil.
<br/>+ 16rF1 -> nil.
<br/>+ 16rF2 -> nil.
<br/>+ 16rF3 -> nil.
<br/>+ 16rF4 -> nil.
<br/>+ 16rF5 -> nil.
<br/>+ 16rF6 -> #'VK_ATTN'.
<br/>+ 16rF7 -> #'VK_CRSEL'.
<br/>+ 16rF8 -> #'VK_EXSEL'.
<br/>+ 16rF9 -> #'VK_EREOF'. "Erase EOF key"
<br/>+ 16rFA -> #'VK_PLAY'.
<br/>+ 16rFB -> #'VK_ZOOM'.
<br/>+ 16rFC -> #'VK_NONAME'. "Reserved"
<br/>+ 16rFD -> #'VK_PA1'.
<br/>+ 16rFE -> #'VK_OEM_CLEAR'. "Clear key"
<br/>+
<br/>+ }!
<br/><br/>Item was added:
<br/>+ ----- Method: EventSensor class>>virtualKeysOnX11 (in category 'virtual keys') -----
<br/>+ virtualKeysOnX11
<br/>+ "Based on the OSVM X11 code as of 202104182333"
<br/>+ "<a href="https://code.woboq.org/kde/include/X11/keysymdef.h.html" target="_top" rel="nofollow" link="external">https://code.woboq.org/kde/include/X11/keysymdef.h.html</a>"
<br/>+
<br/>+ "!!!!!! There are non-printable control keys for keyDown events on X11. Sigh."
<br/>+ 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."
<br/>+ ^ {
<br/>+
<br/>+ "Regular ASCII"
<br/>+ 16r41 -> $A.
<br/>+ 16r42 -> $B.
<br/>+ 16r43 -> $C.
<br/>+ 16r44 -> $D.
<br/>+ 16r45 -> $E.
<br/>+ 16r46 -> $F.
<br/>+ 16r47 -> $G.
<br/>+ 16r48 -> $H.
<br/>+ 16r49 -> $I.
<br/>+ 16r4A -> $J.
<br/>+ 16r4B -> $K.
<br/>+ 16r4C -> $L.
<br/>+ 16r4D -> $M.
<br/>+ 16r4E -> $N.
<br/>+ 16r4F -> $O.
<br/>+ 16r50 -> $P.
<br/>+ 16r51 -> $Q.
<br/>+ 16r52 -> $R.
<br/>+ 16r53 -> $S.
<br/>+ 16r54 -> $T.
<br/>+ 16r55 -> $U.
<br/>+ 16r56 -> $V.
<br/>+ 16r57 -> $W.
<br/>+ 16r58 -> $X.
<br/>+ 16r59 -> $Y.
<br/>+ 16r5A -> $Z.
<br/>+
<br/>+ "Regular ASCII - numbers"
<br/>+ 16r30 -> $0.
<br/>+ 16r31 -> $1.
<br/>+ 16r32 -> $2.
<br/>+ 16r33 -> $3.
<br/>+ 16r34 -> $4.
<br/>+ 16r35 -> $5.
<br/>+ 16r36 -> $6.
<br/>+ 16r37 -> $7.
<br/>+ 16r38 -> $8.
<br/>+ 16r39 -> $9.
<br/>+
<br/>+ "Mapped to uppercase when SHIFT is pressed ... sigh ..."
<br/>+ 16r61 -> $A.
<br/>+ 16r62 -> $B.
<br/>+ 16r63 -> $C.
<br/>+ 16r64 -> $D.
<br/>+ 16r65 -> $E.
<br/>+ 16r66 -> $F.
<br/>+ 16r67 -> $G.
<br/>+ 16r68 -> $H.
<br/>+ 16r69 -> $I.
<br/>+ 16r6A -> $J.
<br/>+ 16r6B -> $K.
<br/>+ 16r6C -> $L.
<br/>+ 16r6D -> $M.
<br/>+ 16r6E -> $N.
<br/>+ 16r6F -> $O.
<br/>+ 16r70 -> $P.
<br/>+ 16r71 -> $Q.
<br/>+ 16r72 -> $R.
<br/>+ 16r73 -> $S.
<br/>+ 16r74 -> $T.
<br/>+ 16r75 -> $U.
<br/>+ 16r76 -> $V.
<br/>+ 16r77 -> $W.
<br/>+ 16r78 -> $X.
<br/>+ 16r79 -> $Y.
<br/>+ 16r7A -> $Z.
<br/>+
<br/>+ "most common non-printable control characters"
<br/>+ 16r01 -> Character home.
<br/>+ 16r03 -> Character enter.
<br/>+ 16r04 -> Character end.
<br/>+ 16r05 -> Character insert.
<br/>+ 16r08 -> Character backspace.
<br/>+ 16r09 -> Character tab.
<br/>+ 16r0B -> Character pageUp.
<br/>+ 16r0C -> Character pageDown.
<br/>+ 16r0D -> Character return.
<br/>+ 16r1B -> Character escape.
<br/>+ 16r1C -> Character arrowLeft.
<br/>+ 16r1D -> Character arrowRight.
<br/>+ 16r1E -> Character arrowUp.
<br/>+ 16r1F -> Character arrowDown.
<br/>+ 16r20 -> Character space.
<br/>+
<br/>+ 16r7F -> Character delete.
<br/>+
<br/>+ "Physical modifier keys"
<br/>+ 16rF7 -> (self mapAltKeysToOptionKeys ifTrue: [#option] ifFalse: [#command "aka. #alt"]). "#'XK_Alt_L'"
<br/>+ 16rFE -> #shift. "#'XK_Shift_R'"
<br/>+ 16rFF -> #shift. "#'XK_Shift_L'."
<br/>+ 16rFA -> (self mapControlKeysToCommandKeys ifTrue: [#command] ifFalse: [#control]). "#'XK_Control_R'"
<br/>+ 16rFB -> (self mapControlKeysToCommandKeys ifTrue: [#command] ifFalse: [#control]). "#'XK_Control_L'."
<br/>+ 16rFD -> #capsLock. "#'XK_Caps_Lock'."
<br/>+
<br/>+ "Try to make sense of some other key characters. Hmpf."
<br/>+ 16r22 -> #squeak1.
<br/>+ 16r23 -> #squeak1.
<br/>+ 16r27 -> #squeak1.
<br/>+ 16r2D -> #squeak1.
<br/>+ 16r2F -> #squeak1.
<br/>+ 16r3A -> #squeak1.
<br/>+ 16r3B -> #squeak1.
<br/>+ 16r3C -> #squeak1.
<br/>+ 16r3E -> #squeak1.
<br/>+ 16r3F -> #squeak1.
<br/>+ 16r5B -> #squeak1.
<br/>+ 16r5C -> #squeak1.
<br/>+ 16r5E -> #squeak1.
<br/>+ 16r5F -> #squeak1.
<br/>+ 16r60 -> #squeak1.
<br/>+ 16r7B -> #squeak1.
<br/>+ 16r7C -> #squeak1.
<br/>+ 16r7E -> #squeak1.
<br/>+ 16rC2 -> #squeak1.
<br/>+ 16rC3 -> #squeak1.
<br/>+
<br/>+ 16r2A -> #squeak2.
<br/>+ 16r2B -> #squeak2.
<br/>+ 16r3D -> #squeak2.
<br/>+ 16r5D -> #squeak2.
<br/>+ 16r7D -> #squeak2.
<br/>+
<br/>+ 16r2C -> #squeakComma.
<br/>+ 16r2E -> #squeakPeriod.
<br/>+
<br/>+ }!
<br/><br/>Item was changed:
<br/> ----- Method: EventSensor>>processEvent: (in category 'private-I/O') -----
<br/> processEvent: evt
<br/> "Process a single event. This method is run at high priority."
<br/> | type buttons window |
<br/> type := evt at: 1.
<br/> lastEventTime := evt at: 2.
<br/>
<br/> "Only process main window events, forward others to host window proxies"
<br/> window := evt at: 8.
<br/> (window isNil or: [window isZero]) ifTrue:
<br/> [window := 1.
<br/> evt at: 8 put: window].
<br/> window = 1 ifFalse: [
<br/> ^Smalltalk at: #HostWindowProxy ifPresent: [:w | w processEvent: evt]].
<br/>
<br/> "Tackle mouse events and mouse wheel events first"
<br/> (type = EventTypeMouse or: [type = EventTypeMouseWheel])
<br/> ifTrue: [buttons := (ButtonDecodeTable at: (evt at: 5) + 1).
<br/> evt at: 5 put: (Smalltalk platformName = 'Mac OS'
<br/> ifTrue: [ buttons ]
<br/> ifFalse: [ self mapButtons: buttons modifiers: (evt at: 6) ]).
<br/> self queueEvent: evt.
<br/> type = EventTypeMouseWheel
<br/> ifTrue: [^ self processMouseWheelEvent: evt].
<br/> type = EventTypeMouse
<br/> ifTrue: [^ self processMouseEvent: evt]].
<br/>
<br/> "Store the event in the queue if there's any"
<br/> type = EventTypeKeyboard
<br/> ifTrue: [ "Check if the event is a user interrupt"
<br/> ((evt at: 4) = EventKeyChar
<br/> and: [((evt at: 3)
<br/> bitOr: (((evt at: 5)
<br/> bitAnd: 8)
<br/> bitShift: 8))
<br/> = interruptKey])
<br/> ifTrue: ["interrupt key is meta - not reported as event"
<br/> ^ interruptSemaphore signal].
<br/> "Decode keys for characters (e.g., map ctrl -> cmd)."
<br/> (evt at: 4) = EventKeyChar
<br/> ifTrue: [ | unicode ascii |
<br/> "Copy lookup key first in case of key swap."
<br/> unicode := {evt at: 6. evt at: 5}.
<br/> ascii := {evt at: 3. evt at: 5}.
<br/> KeyDecodeTable "Unicode character first"
<br/> at: unicode
<br/> ifPresent: [:a | evt at: 6 put: a first;
<br/> at: 5 put: a second].
<br/> KeyDecodeTable "ASCII character second"
<br/> at: ascii
<br/> ifPresent: [:a | evt at: 3 put: a first;
<br/>+ at: 5 put: a second]]
<br/>+ ifFalse: ["Replace modifiers for virtual keys. (keyUp/keyDown)"
<br/>+ VirtualKeyTable
<br/>+ at: ((evt at: 5) bitShift: 8)
<br/>+ ifPresent: [:a | evt at: 5 put: a]].
<br/>- at: 5 put: a second]].
<br/> self queueEvent: evt.
<br/> self processKeyboardEvent: evt .
<br/> ^self ].
<br/>
<br/> "Handle all events other than Keyboard or Mouse."
<br/> self queueEvent: evt.
<br/> !
<br/><br/>Item was changed:
<br/>+ (PackageInfo named: 'Kernel') postscript: 'EventSensor initialize..
<br/>+ EventSensor startUp..'!
<br/>- (PackageInfo named: 'Kernel') postscript: 'EventSensor initialize.
<br/>- EventSensor startUp.'!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130491
The Trunk: Collections-mt.945.mcz
2021-06-17T23:02:53Z
2021-06-17T23:02:53Z
commits-2
Marcel Taeumel uploaded a new version of Collections to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Collections-mt.945.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Collections-mt.945.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Collections-mt.945
<br/>Author: mt
<br/>Time: 18 June 2021, 8:02:50.788904 am
<br/>UUID: d551c74f-90b4-400a-8952-d9d4ff31e3bb
<br/>Ancestors: Collections-eem.944
<br/><br/>Extends constant character names to support #return.
<br/><br/>Fixes constant character names to work with all current constants, which, e.g., includes #arrowUp etc.
<br/><br/>Drop #newPage in favor of #pageDown (and #pageUp). Note that #newPage still works as a constant. It will just not show up when you print a non-printable character.
<br/><br/>=============== Diff against Collections-eem.944 ===============
<br/><br/>Item was changed:
<br/> ----- Method: Character class>>constantNames (in category 'private') -----
<br/> constantNames
<br/>+ ^ #( backspace delete return lf enter delete escape null space tab arrowDown arrowUp arrowLeft arrowRight end home pageDown pageUp euro insert )!
<br/>- ^ #( backspace cr delete escape lf null newPage space tab ).!
<br/><br/>Item was added:
<br/>+ ----- Method: Character class>>return (in category 'accessing untypeable characters') -----
<br/>+ return
<br/>+ "Answer the Character representing a carriage return."
<br/>+
<br/>+ ^self value: 13!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130482
The Trunk: Graphics-eem.449.mcz
2021-06-17T10:46:56Z
2021-06-17T10:46:56Z
commits-2
Eliot Miranda uploaded a new version of Graphics to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Graphics-eem.449.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Graphics-eem.449.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Graphics-eem.449
<br/>Author: eem
<br/>Time: 17 June 2021, 10:46:52.453492 am
<br/>UUID: b792d8b6-a478-4227-9a11-c89a70cb3622
<br/>Ancestors: Graphics-mt.448
<br/><br/>Simplify initializing Forms and allow 64-bit arrays to be used as bitmaps.
<br/><br/>=============== Diff against Graphics-mt.448 ===============
<br/><br/>Item was changed:
<br/> ----- Method: Form>>bitsSize (in category 'accessing') -----
<br/> bitsSize
<br/>+ | pixelsPerWord |
<br/>+ depth ifNil: [depth := 1].
<br/>+ pixelsPerWord := 32 // self depth.
<br/>+ ^width + pixelsPerWord - 1 // pixelsPerWord * height!
<br/>- | pixPerWord |
<br/>- depth == nil ifTrue: [depth := 1].
<br/>- pixPerWord := 32 // self depth.
<br/>- ^ width + pixPerWord - 1 // pixPerWord * height!
<br/><br/>Item was changed:
<br/> ----- Method: Form>>setExtent:depth:bits: (in category 'private') -----
<br/> setExtent: extent depth: bitsPerPixel bits: bitmap
<br/> "Create a virtual bit map with the given extent and bitsPerPixel."
<br/>+ | bitsClass |
<br/>+ (width := extent x asInteger) < 0 ifTrue: [width := 0].
<br/>+ (height := extent y asInteger) < 0 ifTrue: [height := 0].
<br/>-
<br/>- width := extent x asInteger.
<br/>- width < 0 ifTrue: [width := 0].
<br/>- height := extent y asInteger.
<br/>- height < 0 ifTrue: [height := 0].
<br/> depth := bitsPerPixel.
<br/>- depth := bitsPerPixel.
<br/> (bits isNil
<br/>+ or: [(bitsClass := bits class) isBits
<br/>+ and: [self bitsSize * 4 "bytes per pixel" = (bitmap size * bitsClass elementSize)]]) ifFalse:
<br/>+ [^self error: 'Bad dimensions and/or bitmap kind'].
<br/>- or:[(bitmap class isWords and: [self bitsSize = bitmap size])
<br/>- or: [bitmap class isBytes and: [self bitsSize * 4 = bitmap size]]])
<br/>- ifFalse:[^self error:'Bad dimensions'].
<br/> bits := bitmap!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130469
Error: All SqueakMap master servers are down
2021-06-17T03:54:55Z
2021-06-17T03:54:55Z
Christoph Thiede
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p>Hi all,</p>
<p><br>
</p>
<p>SqueakMap does not work today:</p>
<p><br>
</p>
<p><img size="14966" contenttype="image/png" id="img151469" style="max-width: 99.9%; user-select: none;" contextid="img74405" tabindex="0" src="https://forum.world.st/attachment/5130469/0/pastedImage.png"><br>
</p>
<div id="Signature">
<div id="divtagdefaultwrapper" dir="ltr" style="font-size: 12pt; color: rgb(0, 0, 0); font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols;">
<div name="divtagdefaultwrapper" style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:; margin:0">
<div>
<div class="_rp_T4" id="Item.MessagePartBody">
<div class="_rp_U4 ms-font-weight-regular ms-font-color-neutralDark rpHighlightAllClass rpHighlightBodyClass" id="Item.MessageUniqueBody" style="font-family:wf_segoe-ui_normal,"Segoe UI","Segoe WP",Tahoma,Arial,sans-serif,serif,EmojiFont">
<div dir="ltr">
<div id="divtagdefaultwrapper"><font face="Calibri,Helvetica,sans-serif,EmojiFont,Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols">
<div id="Signature">
<div style="margin:0px"><font style="font-family:Calibri,Arial,Helvetica,sans-serif,serif,EmojiFont">
<div><font size="3" color="black"><span style="font-size:12pt"><a href="http://www.hpi.de/" target="_blank" rel="nofollow" id="LPNoLP" link="external"><font size="2"><span id="LPlnk909538"><font color="#757B80"></font></span></font></a></span></font></div>
</font></div>
</div>
</font></div>
</div>
</div>
</div>
<div class="_rp_T4" id="Item.MessagePartBody"><br>
</div>
<div class="_rp_T4" id="Item.MessagePartBody">Is there anyone who could fix a server? :-)</div>
<div class="_rp_T4" id="Item.MessagePartBody"><br>
</div>
<div class="_rp_T4" id="Item.MessagePartBody">Best,</div>
<div class="_rp_T4" id="Item.MessagePartBody">Christoph</div>
</div>
<div><font size="2" color="#808080"></font></div>
</div>
</div>
</div>
</div>
<br /><br/>
<div class="signature weak-color">
Carpe Squeak!
</div>
tag:forum.world.st,2006:post-5130186
Speech.sar is missing
2021-05-31T08:54:50Z
2021-05-31T08:54:50Z
Christoph Thiede
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p>Hi all,</p>
<p><br>
</p>
<p>I tried to load the Speech package from SqueakMap into a current Trunk image, but the installation fails because the <span>Speech-Phonetics category seems to be missing in the SAR package. Would it be possible to update the SAR with this package or is the
dependency structure more complicated than I am assuming?</span></p>
<p><span><br>
</span></p>
<p><span>Thanks in advance!</span></p>
<p><span><br>
</span></p>
<p>Best,</p>
<p>Christoph</p>
<div id="Signature">
<div id="divtagdefaultwrapper" dir="ltr" style="font-size: 12pt; color: rgb(0, 0, 0); font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols;">
<div name="divtagdefaultwrapper" style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:; margin:0">
<div>
<div class="_rp_T4" id="Item.MessagePartBody">
<div class="_rp_U4 ms-font-weight-regular ms-font-color-neutralDark rpHighlightAllClass rpHighlightBodyClass" id="Item.MessageUniqueBody" style="font-family:wf_segoe-ui_normal,"Segoe UI","Segoe WP",Tahoma,Arial,sans-serif,serif,EmojiFont">
<div dir="ltr">
<div id="divtagdefaultwrapper"><font face="Calibri,Helvetica,sans-serif,EmojiFont,Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols">
<div id="Signature">
<div style="margin:0px"><font style="font-family:Calibri,Arial,Helvetica,sans-serif,serif,EmojiFont">
<div><font size="3" color="black"><span style="font-size:12pt"><a href="http://www.hpi.de/" target="_blank" rel="nofollow" id="LPNoLP" link="external"><font size="2"><span id="LPlnk909538"><font color="#757B80"></font></span></font></a></span></font></div>
</font></div>
</div>
</font></div>
</div>
</div>
</div>
</div>
<div><font size="2" color="#808080"></font></div>
</div>
</div>
</div>
</div>
<br /><br/>
<div class="signature weak-color">
Carpe Squeak!
</div>
tag:forum.world.st,2006:post-5130415
The Inbox: System-ct.1236.mcz
2021-06-15T07:00:45Z
2021-06-15T07:00:45Z
commits-2
A new version of System was added to project The Inbox:
<br/><a href="http://source.squeak.org/inbox/System-ct.1236.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/inbox/System-ct.1236.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: System-ct.1236
<br/>Author: ct
<br/>Time: 15 June 2021, 4:00:40.522222 pm
<br/>UUID: f7bb410f-d6de-b242-b769-a558aa5a4254
<br/>Ancestors: System-dtl.1235
<br/><br/>Fixes RealEstateAgent intolerance with a nil world which must be handled according to senders. Document the fact that world can be nil in all relevant senders. I struggled about this when I encountered a recursive project error. See StandardSystemView >> #initialFrame.
<br/><br/>=============== Diff against System-dtl.1235 ===============
<br/><br/>Item was changed:
<br/> ----- Method: RealEstateAgent class>>initialFrameAtPointerFor:initialExtent:world: (in category 'framing - private') -----
<br/>+ initialFrameAtPointerFor: aView initialExtent: scaledExtent world: aWorldOrNil
<br/>+ ^((aWorldOrNil ifNil: [0 @ 0] ifNotNil: [aWorldOrNil cursorPoint - (50@10) "puts use with the mouse ptr just to the right of the menu button"])
<br/>- initialFrameAtPointerFor: aView initialExtent: scaledExtent world: aWorld
<br/>- ^(aWorld cursorPoint - (50@10) "puts use with the mouse ptr just to the right of the menu button"
<br/> extent: scaledExtent)
<br/>+ translatedAndSquishedToBeWithin: (self maximumUsableAreaInWorld: aWorldOrNil)!
<br/>- translatedAndSquishedToBeWithin: (self maximumUsableAreaInWorld: aWorld)!
<br/><br/>Item was changed:
<br/> ----- Method: RealEstateAgent class>>initialFrameFor:initialExtent:world: (in category 'framing') -----
<br/>+ initialFrameFor: aView initialExtent: initialExtent world: aWorldOrNil
<br/>- initialFrameFor: aView initialExtent: initialExtent world: aWorld
<br/> | scaledExtent |
<br/> scaledExtent := (initialExtent * self scaleFactor) rounded.
<br/>
<br/> self placeWindowsAtPointer ifTrue:
<br/>+ [^self initialFrameAtPointerFor: aView initialExtent: scaledExtent world: aWorldOrNil].
<br/>- [^self initialFrameAtPointerFor: aView initialExtent: scaledExtent world: aWorld].
<br/>
<br/> ^ Preferences reverseWindowStagger
<br/>+ ifTrue: [self strictlyStaggeredInitialFrameFor: aView initialExtent: scaledExtent world: aWorldOrNil]
<br/>+ ifFalse: [self normalInitialFrameFor: aView initialExtent: scaledExtent world: aWorldOrNil]!
<br/>- ifTrue: [self strictlyStaggeredInitialFrameFor: aView initialExtent: scaledExtent world: aWorld]
<br/>- ifFalse: [self normalInitialFrameFor: aView initialExtent: scaledExtent world: aWorld]!
<br/><br/>Item was changed:
<br/> ----- Method: RealEstateAgent class>>initialFrameFor:world: (in category 'framing') -----
<br/>+ initialFrameFor: aView world: aWorldOrNil
<br/>- initialFrameFor: aView world: aWorld
<br/> "Find a plausible initial screen area for the supplied view. See called method."
<br/>
<br/>+ ^ self initialFrameFor: aView initialExtent: aView initialExtent world: aWorldOrNil!
<br/>- ^ self initialFrameFor: aView initialExtent: aView initialExtent world: aWorld!
<br/><br/>Item was changed:
<br/> ----- Method: RealEstateAgent class>>normalInitialFrameFor:initialExtent:world: (in category 'framing - private') -----
<br/>+ normalInitialFrameFor: aView initialExtent: initialExtent world: aWorldOrNil
<br/>- normalInitialFrameFor: aView initialExtent: initialExtent world: aWorld
<br/> "Find a plausible initial screen area for the supplied view, which should be a StandardSystemView, taking into account the 'reverseWindowStagger' Preference, the size needed, and other windows currently on the screen."
<br/>
<br/> | allOrigins screenRight screenBottom putativeOrigin putativeFrame allowedArea staggerOrigin otherFrames |
<br/>
<br/>+ allowedArea := self maximumUsableAreaInWorld: aWorldOrNil.
<br/>- allowedArea := self maximumUsableAreaInWorld: aWorld.
<br/> screenRight := allowedArea right.
<br/> screenBottom := allowedArea bottom.
<br/>
<br/> otherFrames := Smalltalk isMorphic
<br/>+ ifTrue: [(SystemWindow windowsIn: aWorldOrNil satisfying: [:w | w isCollapsed not])
<br/>- ifTrue: [(SystemWindow windowsIn: aWorld satisfying: [:w | w isCollapsed not])
<br/> collect: [:w | w bounds]]
<br/> ifFalse: [ScheduledControllers scheduledWindowControllers
<br/> select: [:aController | aController view ~~ nil]
<br/> thenCollect: [:aController | aController view isCollapsed
<br/> ifTrue: [aController view expandedFrame]
<br/> ifFalse: [aController view displayBox]]].
<br/>
<br/> allOrigins := otherFrames collect: [:f | f origin].
<br/>+ (self standardPositionsInWorld: aWorldOrNil) do: "First see if one of the standard positions is free"
<br/>- (self standardPositionsInWorld: aWorld) do: "First see if one of the standard positions is free"
<br/> [:aPosition | (allOrigins includes: aPosition)
<br/> ifFalse:
<br/> [^ (aPosition extent: initialExtent) translatedAndSquishedToBeWithin: allowedArea]].
<br/>
<br/>+ staggerOrigin := (self standardPositionsInWorld: aWorldOrNil) first. "Fallback: try offsetting from top left"
<br/>- staggerOrigin := (self standardPositionsInWorld: aWorld) first. "Fallback: try offsetting from top left"
<br/> putativeOrigin := staggerOrigin.
<br/>
<br/> [putativeOrigin := putativeOrigin + StaggerOffset.
<br/> putativeFrame := putativeOrigin extent: initialExtent.
<br/> (putativeFrame bottom < screenBottom) and:
<br/> [putativeFrame right < screenRight]]
<br/> whileTrue:
<br/> [(allOrigins includes: putativeOrigin)
<br/> ifFalse:
<br/> [^ (putativeOrigin extent: initialExtent) translatedAndSquishedToBeWithin: allowedArea]].
<br/> ^ (self scrollBarSetback @ self screenTopSetback extent: initialExtent) translatedAndSquishedToBeWithin: allowedArea!
<br/><br/>Item was changed:
<br/> ----- Method: RealEstateAgent class>>strictlyStaggeredInitialFrameFor:initialExtent:world: (in category 'framing - private') -----
<br/>+ strictlyStaggeredInitialFrameFor: aStandardSystemView initialExtent: initialExtent world: aWorldOrNil
<br/>- strictlyStaggeredInitialFrameFor: aStandardSystemView initialExtent: initialExtent world: aWorld
<br/> "This method implements a staggered window placement policy that I (di) like.
<br/> Basically it provides for up to 4 windows, staggered from each of the 4 corners.
<br/> The windows are staggered so that there will always be a corner visible."
<br/>
<br/> | allowedArea grid initialFrame otherFrames cornerSel corner delta putativeCorner free maxLevel |
<br/>
<br/>+ allowedArea :=(self maximumUsableAreaInWorld: aWorldOrNil)
<br/>- allowedArea :=(self maximumUsableAreaInWorld: aWorld)
<br/> insetBy: (self scrollBarSetback @ self screenTopSetback extent: 0@0).
<br/> "Number to be staggered at each corner (less on small screens)"
<br/> maxLevel := allowedArea area > 300000 ifTrue: [3] ifFalse: [2].
<br/> "Amount by which to stagger (less on small screens)"
<br/> grid := allowedArea area > 500000 ifTrue: [40] ifFalse: [20].
<br/> initialFrame := 0@0 extent: ((initialExtent
<br/> "min: (allowedArea extent - (grid*(maxLevel+1*2) + (grid//2))))
<br/> min: 600@400")).
<br/> otherFrames := Smalltalk isMorphic
<br/>+ ifTrue: [(SystemWindow windowsIn: aWorldOrNil satisfying: [:w | w isCollapsed not])
<br/>- ifTrue: [(SystemWindow windowsIn: aWorld satisfying: [:w | w isCollapsed not])
<br/> collect: [:w | w bounds]]
<br/> ifFalse: [ScheduledControllers scheduledWindowControllers
<br/> select: [:aController | aController view ~~ nil]
<br/> thenCollect: [:aController | aController view isCollapsed
<br/> ifTrue: [aController view expandedFrame]
<br/> ifFalse: [aController view displayBox]]].
<br/> 0 to: maxLevel do:
<br/> [:level |
<br/> 1 to: 4 do:
<br/> [:ci | cornerSel := #(topLeft topRight bottomRight bottomLeft) at: ci.
<br/> corner := allowedArea perform: cornerSel.
<br/> "The extra grid//2 in delta helps to keep title tabs distinct"
<br/> delta := (maxLevel-level*grid+(grid//2)) @ (level*grid).
<br/> 1 to: ci-1 do: [:i | delta := delta rotateBy: #right centerAt: 0@0]. "slow way"
<br/> putativeCorner := corner + delta.
<br/> free := true.
<br/> otherFrames do:
<br/> [:w |
<br/> free := free & ((w perform: cornerSel) ~= putativeCorner)].
<br/> free ifTrue:
<br/> [^ (initialFrame align: (initialFrame perform: cornerSel)
<br/> with: putativeCorner)
<br/> translatedAndSquishedToBeWithin: allowedArea]]].
<br/> "If all else fails..."
<br/> ^ (self scrollBarSetback @ self screenTopSetback extent: initialFrame extent)
<br/> translatedAndSquishedToBeWithin: allowedArea!
<br/><br/><br/>
tag:forum.world.st,2006:post-5129820
Unable to load class with pool dictionary using Monticello
2021-05-18T04:21:25Z
2021-05-18T04:21:25Z
Christoph Thiede
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p>Hi all,</p>
<p><br>
</p>
<p>while loading a class (MyClass) with an attached pool dictionary (MyPool) today using Monticello, I encountered an error from MCPackageLoader which states:</p>
<p><br>
</p>
<blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;">
<p></p>
<div>Warning: This package depends on the following classes:</div>
<p></p>
<p></p>
<div>MyPool</div>
<p></p>
</blockquote>
<p></p>
<div><br>
</div>
<div>This error message does not make sense to me since MyPool is not a class but a pool dictionary. But in MCClassDefinition >> #requirements, all #<span>poolDictionaries are explicitly added to the list of required items. If I exclude them from this list,
I get a warning "</span><span style="font-size: 12pt;">The pool dictionary MyPool does not exist. </span><span style="font-size: 12pt;">Do you want it automatically created?" later from Class >> #sharing:. Is this a bug?</span></div>
<div><span style="font-size: 12pt;"><br>
</span></div>
<div><span style="font-size: 12pt;">I also tried to manually add the pool dictionary initialization (<span>Smalltalk at: #MyPool put: Dictionary new) into the preamble of the package, but this preamble is also evaluated too late (i.e., not before the dependency
warning is raised. Also, this feels a bit too redundant to me.</span></span><span></span></div>
<div><span style="font-size: 12pt;"><span><br>
</span></span></div>
<div><span style="font-size: 12pt;"><span>Do we need a new subclass of MCDefinition to create pool dictionaries automatically? Or could we just remove the confirmation dialog in Class >> #sharing: so that new pools will automatically be created, especially
in non-interactive CI contexts?</span></span></div>
<div><span><br>
</span></div>
<div><span>Best,</span></div>
<div><span>Christoph</span></div>
<p></p>
<div id="Signature">
<div id="divtagdefaultwrapper" dir="ltr" style="font-size: 12pt; color: rgb(0, 0, 0); font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols;">
<div name="divtagdefaultwrapper" style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:; margin:0">
<div>
<div class="_rp_T4" id="Item.MessagePartBody">
<div class="_rp_U4 ms-font-weight-regular ms-font-color-neutralDark rpHighlightAllClass rpHighlightBodyClass" id="Item.MessageUniqueBody" style="font-family:wf_segoe-ui_normal,"Segoe UI","Segoe WP",Tahoma,Arial,sans-serif,serif,EmojiFont">
<div dir="ltr">
<div id="divtagdefaultwrapper"><font face="Calibri,Helvetica,sans-serif,EmojiFont,Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols">
<div id="Signature">
<div style="margin:0px"><font style="font-family:Calibri,Arial,Helvetica,sans-serif,serif,EmojiFont">
<div><font size="3" color="black"><span style="font-size:12pt"><a href="http://www.hpi.de/" target="_blank" rel="nofollow" id="LPNoLP" link="external"><font size="2"><span id="LPlnk909538"><font color="#757B80"></font></span></font></a></span></font></div>
</font></div>
</div>
</font></div>
</div>
</div>
</div>
</div>
<div><font size="2" color="#808080"></font></div>
</div>
</div>
</div>
</div>
<br /><br/>
<div class="signature weak-color">
Carpe Squeak!
</div>
tag:forum.world.st,2006:post-5130423
The Inbox: Morphic-ct.1774.mcz
2021-06-15T09:50:47Z
2021-06-15T09:50:47Z
commits-2
A new version of Morphic was added to project The Inbox:
<br/><a href="http://source.squeak.org/inbox/Morphic-ct.1774.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/inbox/Morphic-ct.1774.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-ct.1774
<br/>Author: ct
<br/>Time: 15 June 2021, 6:50:38.559902 pm
<br/>UUID: f5614a67-386a-ee4c-9683-44b338df60dd
<br/>Ancestors: Morphic-mt.1773
<br/><br/>Allows models to honor the currently hovered column position in a PluggableMultiColumnListMorph for mouse actions such as tool-tips or double-click events.
<br/><br/>Usage examples:
<br/><br/> multiColumnList getHelpSelector: #helpAtRow:atColumn:.
<br/> multiColumnList doubleClickSelector: #doubleClickColumn:.
<br/><br/>=============== Diff against Morphic-mt.1773 ===============
<br/><br/>Item was changed:
<br/> PluggableListMorph subclass: #PluggableMultiColumnListMorph
<br/>+ instanceVariableNames: 'listMorphs hoverColumn'
<br/>- instanceVariableNames: 'listMorphs'
<br/> classVariableNames: ''
<br/> poolDictionaries: ''
<br/> category: 'Morphic-Pluggable Widgets'!
<br/>
<br/> !PluggableMultiColumnListMorph commentStamp: '<historical>' prior: 0!
<br/> This morph can be used to show a list having multiple columns, The columns are self width sized to make the largest entry in each list fit. In some cases the pane may then be too narrow.
<br/>
<br/> Use it like a regular PluggableListMorph except pass in an array of lists instead of a single list.
<br/>
<br/> There are base assumptions made here that each list in the array of lists is the same size.
<br/>
<br/> Also, the highlight color for the selection is easy to modify in the #highlightSelection method. I used blue
<br/> when testing just to see it work.!
<br/><br/>Item was added:
<br/>+ ----- Method: PluggableMultiColumnListMorph>>balloonText (in category 'accessing') -----
<br/>+ balloonText
<br/>+
<br/>+ | columnIndex modelIndex selector |
<br/>+ selector := self getHelpSelector ifNil: [^ super balloonText].
<br/>+ (self model respondsTo: selector) ifFalse: [^ nil].
<br/>+
<br/>+ modelIndex := self modelIndexFor: self hoverRow.
<br/>+ modelIndex > 0 ifFalse: [^ nil].
<br/>+ columnIndex := self hoverColumn.
<br/>+ columnIndex > 0 ifFalse: [^ nil].
<br/>+ ^ self model perform: selector withEnoughArguments: {modelIndex. columnIndex}!
<br/><br/>Item was added:
<br/>+ ----- Method: PluggableMultiColumnListMorph>>columnAtLocation: (in category 'accessing - items') -----
<br/>+ columnAtLocation: aPoint
<br/>+ "Return the index of the column at the given point or 0 if outside"
<br/>+
<br/>+ | pointInListMorphCoords |
<br/>+ pointInListMorphCoords := (self scroller transformFrom: self) transform: aPoint.
<br/>+
<br/>+ ^ listMorphs findFirst: [:listMorph |
<br/>+ pointInListMorphCoords x between: listMorph left and: listMorph right]!
<br/><br/>Item was added:
<br/>+ ----- Method: PluggableMultiColumnListMorph>>doubleClick: (in category 'event handling') -----
<br/>+ doubleClick: event
<br/>+
<br/>+ | rowIndex columnIndex |
<br/>+ doubleClickSelector ifNil: [^ super doubleClick: event].
<br/>+
<br/>+ rowIndex := self rowAtLocation: event position.
<br/>+ rowIndex = 0 ifTrue: [^ super doubleClick: event].
<br/>+ columnIndex := self columnAtLocation: event position.
<br/>+ "selectedMorph ifNil: [self setSelectedMorph: aMorph]."
<br/>+ ^ self model perform: doubleClickSelector withEnoughArguments: {columnIndex}!
<br/><br/>Item was added:
<br/>+ ----- Method: PluggableMultiColumnListMorph>>handleMouseMove: (in category 'events-processing') -----
<br/>+ handleMouseMove: anEvent
<br/>+
<br/>+ anEvent wasHandled ifTrue: [^ self].
<br/>+
<br/>+ super handleMouseMove: anEvent.
<br/>+
<br/>+ self hoverColumn: (self columnAtLocation: anEvent position).!
<br/><br/>Item was added:
<br/>+ ----- Method: PluggableMultiColumnListMorph>>hoverColumn (in category 'accessing') -----
<br/>+ hoverColumn
<br/>+
<br/>+ ^ hoverColumn ifNil: [0]!
<br/><br/>Item was added:
<br/>+ ----- Method: PluggableMultiColumnListMorph>>hoverColumn: (in category 'accessing') -----
<br/>+ hoverColumn: viewIndex
<br/>+
<br/>+ hoverColumn := viewIndex.
<br/>+
<br/>+ self wantsBalloon ifTrue: [
<br/>+ self activeHand
<br/>+ removePendingBalloonFor: self;
<br/>+ triggerBalloonFor: self after: self balloonHelpDelayTime].!
<br/><br/>Item was changed:
<br/> ----- Method: PluggableMultiColumnListMorph>>hoverRow: (in category 'accessing') -----
<br/> hoverRow: viewIndex
<br/>
<br/> hoverRow = viewIndex ifTrue: [^ self].
<br/>+ hoverRow = 0 ifTrue: [self hoverColumn: 0].
<br/> listMorphs do: [:listMorph |
<br/> listMorph rowChanged: hoverRow with: viewIndex].
<br/> super hoverRow: viewIndex.!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130416
The Inbox: Morphic-ct.1773.mcz
2021-06-15T07:01:04Z
2021-06-15T07:01:04Z
commits-2
A new version of Morphic was added to project The Inbox:
<br/><a href="http://source.squeak.org/inbox/Morphic-ct.1773.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/inbox/Morphic-ct.1773.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-ct.1773
<br/>Author: ct
<br/>Time: 15 June 2021, 4:00:56.918222 pm
<br/>UUID: ba7ea6ab-c067-de4a-8f66-ce6a218d4ae5
<br/>Ancestors: Morphic-mt.1771
<br/><br/>Complements System-ct.1236.
<br/><br/>=============== Diff against Morphic-mt.1771 ===============
<br/><br/>Item was changed:
<br/> ----- Method: SystemWindow class>>windowsIn:satisfying: (in category 'top window') -----
<br/>+ windowsIn: aWorldOrNil satisfying: windowBlock
<br/>- windowsIn: aWorld satisfying: windowBlock
<br/> | windows |
<br/>
<br/> windows := OrderedCollection new.
<br/>+ aWorldOrNil ifNil: [^windows]. "opening MVC in Morphic - WOW!!"
<br/>+ aWorldOrNil submorphs do:
<br/>- aWorld ifNil: [^windows]. "opening MVC in Morphic - WOW!!"
<br/>- aWorld submorphs do:
<br/> [:m | | s |
<br/> ((m isSystemWindow) and: [windowBlock value: m])
<br/> ifTrue: [windows addLast: m]
<br/> ifFalse: [((m isKindOf: TransformationMorph) and: [m submorphs size = 1])
<br/> ifTrue: [s := m firstSubmorph.
<br/> ((s isSystemWindow) and: [windowBlock value: s])
<br/> ifTrue: [windows addLast: s]]]].
<br/> ^ windows!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130374
The Trunk: Morphic-mt.1773.mcz
2021-06-13T23:31:57Z
2021-06-13T23:31:57Z
commits-2
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Morphic-mt.1773.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Morphic-mt.1773.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-mt.1773
<br/>Author: mt
<br/>Time: 14 June 2021, 8:31:51.352374 am
<br/>UUID: d4056dd6-8c5f-e045-9c9a-b6b4b34b42a3
<br/>Ancestors: Morphic-ct.1772
<br/><br/>Adds explanation about why not sending super in the recent selectionIndex: fix.
<br/><br/>=============== Diff against Morphic-ct.1772 ===============
<br/><br/>Item was changed:
<br/> ----- Method: PluggableMultiColumnListMorph>>selectionIndex: (in category 'selection') -----
<br/> selectionIndex: viewIndex
<br/>
<br/> listMorphs do: [:listMorph | listMorph selectedRow: (viewIndex min: self listSize)].
<br/>
<br/>+ "ct: As per the invariant defined in #setListParameters, listMorphs always includes listMorph. Subsequently, every super send in #selectionIndex: would be without effect because #selectionIndex already has been updated in the child class. Since selection highlighting is also not relevant for multi-column list morphs (this hook is only used by SimpleHierarchicalListMorph), we can refuse this bequest but send #scrollSelectionIntoView manually."
<br/> self scrollSelectionIntoView.!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130373
The Trunk: Morphic-ct.1772.mcz
2021-06-13T23:30:05Z
2021-06-13T23:30:05Z
commits-2
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
<br/><a href="http://source.squeak.org/trunk/Morphic-ct.1772.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/trunk/Morphic-ct.1772.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-ct.1772
<br/>Author: ct
<br/>Time: 11 June 2021, 2:25:02.644041 pm
<br/>UUID: d496a0b4-aea8-4543-bb83-5b539cc4dafd
<br/>Ancestors: Morphic-mt.1771
<br/><br/>Fixes automatic scrolling in multi-column list morphs when the selection is changed.
<br/><br/>You can try this out by doing
<br/> SoundLibraryTool new openInWorld setExtentFromHalo: 100 asPoint
<br/>and using your arrow/Home/End keys to navigate in the sound list.
<br/><br/>Reasoning: As per the invariant defined in #setListParameters, listMorphs always includes listMorph. Subsequently, every super send in #selectionIndex: would be without effect because #selectionIndex already has been updated in the child class. Since selection highlighting is also not relevant for multi-column list morphs (this hook is only used by SimpleHierarchicalListMorph), we can refuse this bequest but send #scrollSelectionIntoView manually.
<br/><br/>=============== Diff against Morphic-mt.1771 ===============
<br/><br/>Item was changed:
<br/> ----- Method: PluggableMultiColumnListMorph>>selectionIndex: (in category 'selection') -----
<br/> selectionIndex: viewIndex
<br/>
<br/> listMorphs do: [:listMorph | listMorph selectedRow: (viewIndex min: self listSize)].
<br/>+
<br/>+ self scrollSelectionIntoView.!
<br/>- super selectionIndex: viewIndex.!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130371
ImageSegmentTest>>#testImageSegmentsShouldBeWritableToaFile causes fatal lockup on ARM64 but not on Mac older VM
2021-06-13T19:16:55Z
2021-06-13T19:16:55Z
timrowledge
I just made a new ARM64 VM to try out the #fix_include_order VMMaker branch.
<br/><br/>When running the TestRunner I noticed that the segment test goes into an infinite loop and cannot be interrupted. I'm not all that surprised that the segment loading fails but I an very annoyed that the interrupt fails to do anything. We've spent so much time over the years trying to make that work properly.
<br/><br/>On my Mac running an older 2020 5.3 VM it does not fail.
<br/><br/>tim
<br/>--
<br/>tim Rowledge; <a href="/user/SendEmail.jtp?type=node&node=5130371&i=0" target="_top" rel="nofollow" link="external">[hidden email]</a>; <a href="http://www.rowledge.org/tim" target="_top" rel="nofollow" link="external">http://www.rowledge.org/tim</a><br/>Fractured Idiom:- AMICUS PURIAE - Platonic friend
<br/><br/><br/><br/>
tag:forum.world.st,2006:post-5130322
The Inbox: Collections-ct.947.mcz
2021-06-10T11:41:02Z
2021-06-10T11:41:02Z
commits-2
A new version of Collections was added to project The Inbox:
<br/><a href="http://source.squeak.org/inbox/Collections-ct.947.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/inbox/Collections-ct.947.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Collections-ct.947
<br/>Author: ct
<br/>Time: 10 June 2021, 8:40:58.780588 pm
<br/>UUID: cb2cdf00-2a3a-5d46-bf15-60255480c1fa
<br/>Ancestors: Collections-eem.944
<br/><br/>Proposal: Adds sort function that uses a boolean compare block such as [:a :b | a <= b].
<br/><br/>Usage examples:
<br/><br/> squotVersions sorted: [:a :b | historyWalker shouldVisit: a before: b] asCompareSortFunction.
<br/> #(true nil 42) sorted: #compareSafely: asCompareSortFunction.
<br/><br/>=============== Diff against Collections-eem.944 ===============
<br/><br/>Item was added:
<br/>+ ----- Method: BlockClosure>>asCompareSortFunction (in category '*Collections-SortFunctions-converting') -----
<br/>+ asCompareSortFunction
<br/>+
<br/>+ ^ CompareBlockFunction usingBlock: self!
<br/><br/>Item was changed:
<br/> SortFunction subclass: #CollatorBlockFunction
<br/> instanceVariableNames: 'collatorBlock'
<br/> classVariableNames: ''
<br/> poolDictionaries: ''
<br/> category: 'Collections-SortFunctions'!
<br/>
<br/>+ !CollatorBlockFunction commentStamp: 'ct 6/10/2021 20:38' prior: 0!
<br/>- !CollatorBlockFunction commentStamp: 'nice 11/5/2017 22:57' prior: 0!
<br/> A CollatorBlockFunction is a special SortFunction using a dyadic block to collate objects.
<br/>
<br/> Instance Variables
<br/>
<br/>+ collatorBlock <Block> a dyadic block that must return a -1, 0, or 1.!
<br/>- collator <Block> a dyadic block that must return a -1, 0, or 1.!
<br/><br/>Item was added:
<br/>+ SortFunction subclass: #CompareBlockFunction
<br/>+ instanceVariableNames: 'compareBlock'
<br/>+ classVariableNames: ''
<br/>+ poolDictionaries: ''
<br/>+ category: 'Collections-SortFunctions'!
<br/>+
<br/>+ !CompareBlockFunction commentStamp: 'ct 6/10/2021 20:38' prior: 0!
<br/>+ A CompareBlockFunction is a special SortFunction using a dyadic block to compare objects. The default compare logic is the lower-equals function (#<=).
<br/>+
<br/>+ Instance Variables
<br/>+
<br/>+ compareBlock <Block> a dyadic block that must return true iff the first argument should not appear after the second , otherwise false.!
<br/><br/>Item was added:
<br/>+ ----- Method: CompareBlockFunction class>>usingBlock: (in category 'instance creation') -----
<br/>+ usingBlock: twoArgsBlock
<br/>+
<br/>+ ^ self new compareBlock: twoArgsBlock!
<br/><br/>Item was added:
<br/>+ ----- Method: CompareBlockFunction>>collate:with: (in category 'evaluating') -----
<br/>+ collate: anObject with: anotherObject
<br/>+
<br/>+ ^ (compareBlock value: anObject value: anotherObject)
<br/>+ ifTrue: [-1]
<br/>+ ifFalse: [1]!
<br/><br/>Item was added:
<br/>+ ----- Method: CompareBlockFunction>>compareBlock (in category 'accessing') -----
<br/>+ compareBlock
<br/>+
<br/>+ ^ compareBlock!
<br/><br/>Item was added:
<br/>+ ----- Method: CompareBlockFunction>>compareBlock: (in category 'accessing') -----
<br/>+ compareBlock: aBlock
<br/>+
<br/>+ compareBlock := aBlock.!
<br/><br/>Item was added:
<br/>+ ----- Method: Symbol>>asCompareSortFunction (in category '*Collections-SortFunctions-converting') -----
<br/>+ asCompareSortFunction
<br/>+
<br/>+ ^ CompareBlockFunction usingBlock: self!
<br/><br/><br/>
tag:forum.world.st,2006:post-4450450
Announcement: Spelling services
2012-03-06T09:35:09Z
2012-03-06T09:35:09Z
Tim Felgentreff
Hi
<br/><br/>Once upon a time, John M. McIntosh built a spellchecker plugin for the
<br/>MacVM and there was a fileout that added a spelling service class to use
<br/>it from Squeak. We have added code to provide the same API (for now) to
<br/>windows and linux users that have ispell (or a compatible program, like
<br/>aspell) installed on their systems using system callouts.
<br/><br/>A metacello configuration is available from the MetacelloRepository on
<br/>Squeaksource, ConfigurationOfSpellingServices.
<br/><br/>The development repository is at
<br/><a href="http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/SpellingServices.html" target="_top" rel="nofollow" link="external">http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/SpellingServices.html</a>,
<br/>the repo has global read+write, so if anybody finds this useful and has
<br/>changes, feel free to commit to that repository.
<br/><br/>-Tim
<br/><br/>
tag:forum.world.st,2006:post-5130347
The Inbox: Morphic-ct.1772.mcz
2021-06-11T05:25:10Z
2021-06-11T05:25:10Z
commits-2
A new version of Morphic was added to project The Inbox:
<br/><a href="http://source.squeak.org/inbox/Morphic-ct.1772.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/inbox/Morphic-ct.1772.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: Morphic-ct.1772
<br/>Author: ct
<br/>Time: 11 June 2021, 2:25:02.644041 pm
<br/>UUID: d496a0b4-aea8-4543-bb83-5b539cc4dafd
<br/>Ancestors: Morphic-mt.1771
<br/><br/>Fixes automatic scrolling in multi-column list morphs when the selection is changed.
<br/><br/>You can try this out by doing
<br/> SoundLibraryTool new openInWorld setExtentFromHalo: 100 asPoint
<br/>and using your arrow/Home/End keys to navigate in the sound list.
<br/><br/>Reasoning: As per the invariant defined in #setListParameters, listMorphs always includes listMorph. Subsequently, every super send in #selectionIndex: would be without effect because #selectionIndex already has been updated in the child class. Since selection highlighting is also not relevant for multi-column list morphs (this hook is only used by SimpleHierarchicalListMorph), we can refuse this bequest but send #scrollSelectionIntoView manually.
<br/><br/>=============== Diff against Morphic-mt.1771 ===============
<br/><br/>Item was changed:
<br/> ----- Method: PluggableMultiColumnListMorph>>selectionIndex: (in category 'selection') -----
<br/> selectionIndex: viewIndex
<br/>
<br/> listMorphs do: [:listMorph | listMorph selectedRow: (viewIndex min: self listSize)].
<br/>+
<br/>+ self scrollSelectionIntoView.!
<br/>- super selectionIndex: viewIndex.!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130344
FFI: ConfigurationOfFFI-mt.50.mcz
2021-06-11T01:06:37Z
2021-06-11T01:06:37Z
commits-2
Marcel Taeumel uploaded a new version of ConfigurationOfFFI to project FFI:
<br/><a href="http://source.squeak.org/FFI/ConfigurationOfFFI-mt.50.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/FFI/ConfigurationOfFFI-mt.50.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: ConfigurationOfFFI-mt.50
<br/>Author: mt
<br/>Time: 8 June 2021, 9:59:18.359752 am
<br/>UUID: dd27f133-e636-8e48-843b-10d63987c898
<br/>Ancestors: ConfigurationOfFFI-mt.49
<br/><br/>FFI-Callbacks is compatible with Alien now. So, load it by default when loading Squeak FFI.
<br/><br/>=============== Diff against ConfigurationOfFFI-mt.49 ===============
<br/><br/>Item was changed:
<br/> ----- Method: ConfigurationOfFFI>>baseline20: (in category 'baselines') -----
<br/> baseline20: spec
<br/> <version: '2.0-baseline'>
<br/>
<br/> spec for: #common do: [
<br/> spec blessing: #baseline.
<br/> spec repository: '<a href="http://source.squeakfoundation.org/FFI'" target="_top" rel="nofollow" link="external">http://source.squeakfoundation.org/FFI'</a>.
<br/>
<br/> spec
<br/> package: 'FFI-Pools';
<br/> package: 'FFI-Kernel' with: [ spec requires: 'FFI-Pools' ];
<br/> package: 'FFI-Libraries' with: [ spec requires: 'FFI-Kernel' ];
<br/>+ package: 'FFI-Callbacks' with: [ spec requires: 'FFI-Libraries' ];
<br/>- package: 'FFI-Callbacks' with: [ spec requires: 'FFI-Libraries' ]; "Not compatible with Alien."
<br/>
<br/> package: 'FFI-Tools' with: [ spec requires: 'FFI-Kernel' ];
<br/>
<br/> package: 'FFI-Tests' with: [ spec requires: #('FFI-Kernel' 'FFI-Libraries') ];
<br/> package: 'FFI-PoolsTests' with: [ spec requires: #('FFI-Tests' 'FFI-Pools') ];
<br/> package: 'FFI-CallbacksTests' with: [ spec requires: #('FFI-Tests' 'FFI-Callbacks') ].
<br/>
<br/> spec
<br/>+ group: 'default' with: #(dev);
<br/>+ group: 'dev' with: #('Core' 'Tools' 'Tests');
<br/>- group: 'default' with: #('Core' 'Tools' 'Tests');
<br/>
<br/>+ group: 'Core' with: #('FFI-Kernel' 'FFI-Callbacks');
<br/>- group: 'dev' with: #('Core' 'Libraries' 'Callbacks' 'Tools' 'Tests'); "Not compatible with Alien."
<br/>- group: 'Callbacks' with: #('FFI-Callbacks' 'FFI-CallbacksTests'); "Not compatible with Alien."
<br/>-
<br/>- group: 'Core' with: #('FFI-Kernel');
<br/>- group: 'Libraries' with: #('FFI-Libraries');
<br/> group: 'Tools' with: #('FFI-Tools');
<br/>+ group: 'Tests' with: #('FFI-Tests' 'FFI-PoolsTests' 'FFI-CallbacksTests') ].!
<br/>-
<br/>- group: 'Tests' with: #('FFI-Tests' 'FFI-PoolsTests') ].!
<br/><br/>Item was changed:
<br/> ----- Method: ConfigurationOfFFI>>version20: (in category 'versions') -----
<br/> version20: spec
<br/> <version: '2.0' imports: #('2.0-baseline')>
<br/>
<br/> spec for: #common do: [
<br/> spec
<br/> blessing: #release;
<br/> package: 'FFI-Pools' with: 'FFI-Pools-mt.31';
<br/>+ package: 'FFI-Kernel' with: 'FFI-Kernel-mt.180';
<br/>- package: 'FFI-Kernel' with: 'FFI-Kernel-mt.178';
<br/> package: 'FFI-Libraries' with: 'FFI-Libraries-mt.2';
<br/>+ package: 'FFI-Callbacks' with: 'FFI-Callbacks-mt.25';
<br/>- package: 'FFI-Callbacks' with: 'FFI-Callbacks-mt.21'; "Not compatible with Alien."
<br/>
<br/> package: 'FFI-Tools' with: 'FFI-Tools-mt.37';
<br/>
<br/> package: 'FFI-Tests' with: 'FFI-Tests-mt.51';
<br/> package: 'FFI-PoolsTests' with: 'FFI-PoolsTests-mt.11';
<br/>+ package: 'FFI-CallbacksTests' with: 'FFI-CallbacksTests-mt.4'].!
<br/>- package: 'FFI-CallbacksTests' with: 'FFI-CallbacksTests-mt.2'].!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130343
FFI: ConfigurationOfFFI-mt.49.mcz
2021-06-11T01:06:31Z
2021-06-11T01:06:31Z
commits-2
Marcel Taeumel uploaded a new version of ConfigurationOfFFI to project FFI:
<br/><a href="http://source.squeak.org/FFI/ConfigurationOfFFI-mt.49.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/FFI/ConfigurationOfFFI-mt.49.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: ConfigurationOfFFI-mt.49
<br/>Author: mt
<br/>Time: 27 May 2021, 5:12:51.231087 pm
<br/>UUID: df80231a-0fef-0a4c-926e-bbaa4f673583
<br/>Ancestors: ConfigurationOfFFI-mt.48
<br/><br/>Adds manual (#free) and automatic (#newGC) memory management for callbacks.
<br/><br/>=============== Diff against ConfigurationOfFFI-mt.48 ===============
<br/><br/>Item was changed:
<br/> ----- Method: ConfigurationOfFFI>>version20: (in category 'versions') -----
<br/> version20: spec
<br/> <version: '2.0' imports: #('2.0-baseline')>
<br/>
<br/> spec for: #common do: [
<br/> spec
<br/> blessing: #release;
<br/>+ package: 'FFI-Pools' with: 'FFI-Pools-mt.31';
<br/>+ package: 'FFI-Kernel' with: 'FFI-Kernel-mt.178';
<br/>+ package: 'FFI-Libraries' with: 'FFI-Libraries-mt.2';
<br/>+ package: 'FFI-Callbacks' with: 'FFI-Callbacks-mt.21'; "Not compatible with Alien."
<br/>- package: 'FFI-Pools' with: 'FFI-Pools-mt.30';
<br/>- package: 'FFI-Kernel' with: 'FFI-Kernel-mt.175';
<br/>- package: 'FFI-Libraries' with: 'FFI-Libraries-mt.1';
<br/>- package: 'FFI-Callbacks' with: 'FFI-Callbacks-mt.20'; "Not compatible with Alien."
<br/>
<br/> package: 'FFI-Tools' with: 'FFI-Tools-mt.37';
<br/>
<br/>+ package: 'FFI-Tests' with: 'FFI-Tests-mt.51';
<br/>- package: 'FFI-Tests' with: 'FFI-Tests-mt.50';
<br/> package: 'FFI-PoolsTests' with: 'FFI-PoolsTests-mt.11';
<br/>+ package: 'FFI-CallbacksTests' with: 'FFI-CallbacksTests-mt.2'].!
<br/>- package: 'FFI-CallbacksTests' with: 'FFI-CallbacksTests-mt.1'].!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130342
FFI: ConfigurationOfFFI-mt.48.mcz
2021-06-11T01:06:25Z
2021-06-11T01:06:25Z
commits-2
Marcel Taeumel uploaded a new version of ConfigurationOfFFI to project FFI:
<br/><a href="http://source.squeak.org/FFI/ConfigurationOfFFI-mt.48.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/FFI/ConfigurationOfFFI-mt.48.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: ConfigurationOfFFI-mt.48
<br/>Author: mt
<br/>Time: 27 May 2021, 10:50:35.693247 am
<br/>UUID: fe464aa3-711b-d546-8175-4a47a301f668
<br/>Ancestors: ConfigurationOfFFI-mt.47
<br/><br/>Fixes FFI loading based on Monticello-mt.748 in Squeak 6.0alpha.
<br/><br/>=============== Diff against ConfigurationOfFFI-mt.47 ===============
<br/><br/>Item was changed:
<br/> ----- Method: ConfigurationOfFFI>>version20: (in category 'versions') -----
<br/> version20: spec
<br/> <version: '2.0' imports: #('2.0-baseline')>
<br/>
<br/> spec for: #common do: [
<br/> spec
<br/> blessing: #release;
<br/> package: 'FFI-Pools' with: 'FFI-Pools-mt.30';
<br/>+ package: 'FFI-Kernel' with: 'FFI-Kernel-mt.175';
<br/>- package: 'FFI-Kernel' with: 'FFI-Kernel-mt.174';
<br/> package: 'FFI-Libraries' with: 'FFI-Libraries-mt.1';
<br/> package: 'FFI-Callbacks' with: 'FFI-Callbacks-mt.20'; "Not compatible with Alien."
<br/>
<br/> package: 'FFI-Tools' with: 'FFI-Tools-mt.37';
<br/>
<br/> package: 'FFI-Tests' with: 'FFI-Tests-mt.50';
<br/> package: 'FFI-PoolsTests' with: 'FFI-PoolsTests-mt.11';
<br/> package: 'FFI-CallbacksTests' with: 'FFI-CallbacksTests-mt.1'].!
<br/><br/><br/>
tag:forum.world.st,2006:post-5130341
FFI: ConfigurationOfFFI-mt.47.mcz
2021-06-11T01:06:19Z
2021-06-11T01:06:19Z
commits-2
Marcel Taeumel uploaded a new version of ConfigurationOfFFI to project FFI:
<br/><a href="http://source.squeak.org/FFI/ConfigurationOfFFI-mt.47.mcz" target="_top" rel="nofollow" link="external">http://source.squeak.org/FFI/ConfigurationOfFFI-mt.47.mcz</a><br/><br/>==================== Summary ====================
<br/><br/>Name: ConfigurationOfFFI-mt.47
<br/>Author: mt
<br/>Time: 27 May 2021, 10:02:20.229247 am
<br/>UUID: abc7fa73-456b-5346-b8c7-036c4bfeb478
<br/>Ancestors: ConfigurationOfFFI-mt.46
<br/><br/>I forgot the 'LIbraries' group.
<br/><br/>=============== Diff against ConfigurationOfFFI-mt.46 ===============
<br/><br/>Item was changed:
<br/> ----- Method: ConfigurationOfFFI>>baseline20: (in category 'baselines') -----
<br/> baseline20: spec
<br/> <version: '2.0-baseline'>
<br/>
<br/> spec for: #common do: [
<br/> spec blessing: #baseline.
<br/> spec repository: '<a href="http://source.squeakfoundation.org/FFI'" target="_top" rel="nofollow" link="external">http://source.squeakfoundation.org/FFI'</a>.
<br/>
<br/> spec
<br/> package: 'FFI-Pools';
<br/> package: 'FFI-Kernel' with: [ spec requires: 'FFI-Pools' ];
<br/> package: 'FFI-Libraries' with: [ spec requires: 'FFI-Kernel' ];
<br/> package: 'FFI-Callbacks' with: [ spec requires: 'FFI-Libraries' ]; "Not compatible with Alien."
<br/>
<br/> package: 'FFI-Tools' with: [ spec requires: 'FFI-Kernel' ];
<br/>
<br/> package: 'FFI-Tests' with: [ spec requires: #('FFI-Kernel' 'FFI-Libraries') ];
<br/> package: 'FFI-PoolsTests' with: [ spec requires: #('FFI-Tests' 'FFI-Pools') ];
<br/> package: 'FFI-CallbacksTests' with: [ spec requires: #('FFI-Tests' 'FFI-Callbacks') ].
<br/>
<br/> spec
<br/> group: 'default' with: #('Core' 'Tools' 'Tests');
<br/>
<br/> group: 'dev' with: #('Core' 'Libraries' 'Callbacks' 'Tools' 'Tests'); "Not compatible with Alien."
<br/> group: 'Callbacks' with: #('FFI-Callbacks' 'FFI-CallbacksTests'); "Not compatible with Alien."
<br/>
<br/> group: 'Core' with: #('FFI-Kernel');
<br/>+ group: 'Libraries' with: #('FFI-Libraries');
<br/> group: 'Tools' with: #('FFI-Tools');
<br/>
<br/> group: 'Tests' with: #('FFI-Tests' 'FFI-PoolsTests') ].!
<br/><br/><br/>