TweetFollow Us on Twitter

FKeys, Events
Volume Number:3
Issue Number:9
Column Tag:Forth Forum

FKeys & Events

By Jörg Langowski, MacTutor Editorial Board, Grenoble, France

FKEYs and Events

The example we’ll deal with this time has some history. On a national bulletin board here in France, Calvacom, which has a large section of its activity devoted to the Mac, a proposal was made to write an FKEY that would paste one of a number of character strings into the application currently under use. Thus one would have an easy way to enter ‘boilerplate’ phrases or often used commands into text processors, terminal emulators etc.

I thought this would make a nice example for the Forth column, especially since we hadn’t had an FKEY dealt with yet. In the way of writing this, I discovered several things. First, the simple strategy that comes to mind - taking a string that was saved away somewhere and posting key down events for one character after the other - works only in certain cases, so one has to go a more complicated way (as you’ll see soon). Second, somebody had of course in the meantime written the FKEY under question - in some other language. Nevertheless, still a good Forth example.

Implementing an FKEY

Everyone of you has probably already used one or the other function key, that is, command-shift-number combination. Some might even have written one, its implementation being rather simple. The FKEY resource is a simple subroutine with its entry point at the beginning of its code. It is called from the routine that handles the keyboard. If that routine detects a command-shift-number combination, it will look for the FKEY resource corresponding to the number, and if such a resource is present, load and execute it.

No parameters are passed to the FKEY routine on the stack; we’ll simply set up a local Forth stack on entry to the routine, using LINK, save all registers away, then call the main body of the FKEY, and finally restore the registers and UNLINK A6. This is the standard glue routine for writing kernel-independent Mach2 code which you might already be familiar with. See listing 1.

[One remark with regard to the listing here. This program has been written in Mach2.12 which has a different Toolbox call mechanism than earlier versions. In particular, it expects D4 to point to a common stack low in memory which can be used for all toolbox calls. This stack, and D4, are set up in the Mach2 system. Therefore, to write kernel-independent code, one has to use the old CALL mechanism again. This word is available under a new name: (CALL). If you have an older Mach2 version, simply replace all occurrences of (CALL) with CALL, or redefine the word].

The main body of the FKEY will first look whether it has been called from a bona fide application or whether the topmost window is a dialog or desk accessory. In the latter two cases, the FKEY will do nothing but beep and return. Since the FKEY itself might display a dialog (for editing the text strings), it should not be allowed to redisplay its own dialog when it is already active. Checking whether any dialog is already in place is one way of achieving this; you might think up some more sophisticated ways and change the program accordingly.

If the routine has been called from within a good environment, it will wait for the next key pressed. If the key is a number key, the appropriate message will be posted (see later how this is done). If it is the ‘e’ key, a dialog will be displayed for editing the text strings. In all other cases the routine will simply beep and return.

Posting Events

The first problem that we encounter here is how to post key down events that correspond to the text string into the event queue. Very simple, you’ll say, do the following:

: post.char ( char -- ) 3 swap call post.event drop ;
 : post.string ( string -- )
 count 0 DO dup i + c@ post.char LOOP drop ;

where 3 is the event code for a key down event, and the event message simply contains the character code in the low byte, and no key code (=0). Leaving out the actual key code has so far caused no problem in any case that I tested.

Well, the simple example works. In a way. If the string that is posted is longer than 15 characters, Mach2 will simply beep because it cannot accept more keydown events before switching tasks. This doesn’t have anything to do with the actual length of the event queue or the maximum number of allowed events. It is the application that can’t deal with so many ‘keystrokes’ coming in rapid succession. In addition, of course, if we don’t check the event queue before posting an event, we take the risk of losing it if the maximum number of allowed events (20 by default) has been reached.

This last number can be changed by editing the boot blocks. However, one can think of a more elegant solution that makes the whole process completely independent of the maximum length of the event queue. We allow the posting of a character only if the GetNextEvent routine fetches a null event. In that case we can be sure that not too much activity is going on and the key down event will be handled correctly.

But how do we handle this process? We cannot do some sort of waiting loop within the FKEY, since GetNextEvent will only be called by the application after we have returned. Therefore the FKEY must install a short background routine that monitors the activity of GetNextEvent and posts key down events from the string to be transmitted each time a null event is received. Here the JGNEFilter system global, already used for several examples in MacTutor (V1#9, Bob Denny, and V2#6, JL), comes in very handy. To post a message into the event queue, the post.string word as defined in the listing saves the string and its length away into a defined place and then changes the JGNEFilter vector to point to a custom routine that will post the keystrokes.

The custom routine, GNE.glue, calls GNEIntfc through our standard glue code, which you really know by now. GNEIntfc looks at A1 (which points to the event record), and if a null event is about to be transmitted, it will take the next character from the saved message string and post a key down event under the following conditions:

1. A certain delay has expired since the last character was posted (2 ticks in my example) and

2. The number of pending events is less than a predefined number (here 10).

When the end of the string has been reached, the filter routine resets the JGNEFilter vector to its old value.

Using the method just described, one can transmit strings of arbitrary length to applications. Which is what we wanted.

Editing the text strings

If an ‘e’ is pressed after the FKEY, we’ll display the editing dialog. The Rmaker source for this dialog (ID=2000 for DLOG and DITL, you may want to change this) is in listing 2. It simply consists of 10 editable text items, one OK button and some static text.

The associated Forth word, edit.messages, does a number of things. It first tries to open a resource file named ‘FKEY.messages’ and creates a new one if it doesn’t succeed. By standard, this will be kept in the system folder; leave it there. You can prepare any number of files containing standard messages by renaming them.

The routine then gets the dialog with ID 2000 (it is a shame that FKEYs cannot ‘own’ resources like DRVRs etc. can). If the dialog can’t be found, it beeps and returns; otherwise, it displays the strings from the FKEY.messages file in the boxes for the editable text items. They are 10 individual string-format resources type ‘bplt” with ID=3 to 12 (corresponding to the dialog items 3 to 12). If the resources cannot be found (i.e. the file has just been created and is empty), they are created and initialized with whatever was in the EditText items of the dialog box. In my case, I used the texts ‘Message x’, but you might just leave the strings empty. If the bplt resources are there, they replace the EditText items.

A ModalDialog is then called, allowing the strings to be edited. The only enabled item is the OK button, which returns to the Forth routine. Then, the changed text strings are written back to the bplt resources in the FKEY.messages file, the resource file updated and the dialog disposed of.

Finally, post.message is the routine that is called when a number key is pushed after the FKEY. It gets the bplt resource corresponding to that number and calls post.string (described above) to transmit the string via the GetNextEvent filter routine.

make.fkey creates a file ‘fkey.text’ that contains the FKEY resource and has the correct type and creator to be opened from the FKEY installer (from Quick and Dirty Utilities, Dreams of the Phoenix, Inc., P.O.Box 10273, Jacksonville FL 32247, (904) 396-6952). This file is then packed together with the dialog resources into one file. The FKEY may be installed with the installer; the DLOG 2000 and DITL 2000 must be copied with ResEdit.

Some last notes

As you’ve seen, yet another Mach2 version has been released, v2.12, making v2.11 obsolete only two weeks after I received it. No BIG modifications, only minor ones.

I received some comments from a reader, James Merkel, who mentioned that it would be a good idea for Palo Alto Shipping to release the source for the multitasking kernel as well, now that we have the source of the I/O task. The second comment was to release bug fixes in MacTutor as well as on GEnie, for those not having access to the GEnie Roundtable (including myself). Very good suggestion. PAS, do you listen?

Last, the bulletin board that I mentioned, Calvacom, is now accessible via Tymnet from the US. If you’d like to see what’s going on over here or want to leave me some mail, connect yourself to a Tymnet line and type ‘CalvaCom’ at the login prompt, then ‘nouveau’ when it prompts you for your access code. You can subscribe with your credit card, as usual. Speaking some French helps, of course, but most anybody on the board will understand English. Connect charges (overseas rates included) are of the order of $25 per hour. I’d like to see your feedback in my mailbox!

{1}
Listing 1: Mach2 FKEY for text glossary
( *** Function Key example. JL June 1987 *** )
ONLY FORTH ALSO ASSEMBLER ALSO MAC

4ascii QD15 CONSTANT “qd15
4ascii bplt CONSTANT “bplt
4ascii DITL CONSTANT “ditl
4ascii DLOG CONSTANT “dlog

2 CONSTANT post.delay
 ( 2 ticks wait between posting of characters )
10 CONSTANT max.event  
 ( max # of pending events allowed during posting )
$14a CONSTANT EvQHdr
$29A CONSTANT JGNEFilter
2 CONSTANT QHead
6 CONSTANT QTail
BINARY 0000000000001000 CONSTANT KeyEvent
DECIMAL
 ( header code filled at end of definitions )
header start
 JMP start  ( to be filled later )
header temprect 8 allot
header itemrect 8 allot
header myEventRec 16 allot

: beep 5 (call) sysbeep ;

CODE cmove ( redefine since this is part of Kernel )
 MOVE.L (A6)+,D0
 MOVE.L (A6)+,A1
 MOVE.L (A6)+,A0
 TST.L  D0
 BLE.S  @2
@1 MOVE.B (A0)+,(A1)+
 SUBQ.L #1,D0
 BNE.S  @1
@2 RTS
END-CODE

: / w/ ;

: getFkeyDlg 
 2000 0 -1 (call) GetNewDialog 
;

: #events EvQHdr QTail + @ EvQHdr QHead + @ - 22 / ;

: post.char ( char -- ) 3 swap (call) postEvent drop
 ;

header SavedJGNEFilter 4 allot
header SavedString 256 allot
header bytesToTransfer 4 allot
header lastpost 4 allot

: GNEIntfc { | btt -- }
    getA1 w@ 0= IF
 [‘] bytesToTransfer @ -> btt
 btt IF  (call) tickcount [‘] lastpost @ - post.delay > 
 #events max.events < AND 
 IF
 [‘] SavedString dup c@ btt - 1+
 + c@ post.char
 btt 1- [‘] bytesToTransfer !
 (call) tickcount [‘] lastpost !
 THEN
 ELSE
 [‘] savedJGNEFilter @ JGNEFilter !
 THEN
    THEN
;    
CODE GNE.glue
 LINK A6,#-256 ( 256 bytes of local Forth stack )
 MOVEM.L A0-A5/D0-D7,-(A7)( save registers )
 ( no need for loop return stack )
 ( no parameters are passed )
 JSR GNEintfc  ( call Forth routine )
 MOVEM.L (A7)+,A0-A5/D0-D7( restore registers )
 UNLK A6
 LEA  SavedJGNEFilter,A0
 MOVE.L (A0),A0  ( return address )
 JMP  (A0)
END-CODE

: post.string { string | length -- }
 string c@ -> length
 string [‘] SavedString length 1+ cmove
 length [‘] bytesToTransfer !
 (call) tickcount [‘] lastpost !
 JGNEFilter @ [‘] SavedJGNEFilter !
 [‘] GNE.glue JGNEFilter !
;

: post.message { msg# | dh dPtr tPtr -- }
 “ FKEY.messages” (call) OpenResFile (call) UseResFile
 “bplt msg# 3 + (call) getResource -> dh
 dh IF dh @ post.string
 ELSE beep THEN
;

: edit.messages 
 { | dPtr itemType item box box1 itemHit thandle refnum -- }
 “ FKEY.messages” dup (call) OpenResFile
 (call) ResError 
 IF drop dup (call) CreateResFile
 (call) OpenResFile dup -> refNum 
 (call) UseResFile 
 ELSE dup -> refNum 
 (call) UseResFile drop 
 THEN 
 getFkeyDlg -> dPtr
 dPtr IF
 13 3 DO 
 dPtr i ^ itemType ^ item ^ box
 (call) GetDItem
 item (call) HLock drop
 “bplt i (call) GetResource -> thandle
 thandle IF 
 thandle (call) HLock drop
 item thandle @ (call) SetIText 
 thandle (call) HUnlock drop 
 ELSE
 256 (call) NewHandle drop
 “bplt i “ Message” (call) AddResource
 THEN
 item (call) HUnlock drop
 LOOP ( all messages have been initialized )

 0 ^ itemHit (call) ModalDialog

 13 3 DO 
 dPtr i ^ itemType ^ item ^ box
 (call) GetDItem
 item (call) HLock drop
 “bplt i (call) GetResource -> thandle
 thandle IF 
 thandle (call) HLock drop
 item thandle @ (call) GetIText
 thandle (call) ChangedResource 
 thandle (call) HUnlock drop THEN
 item (call) HUnlock drop
 LOOP ( all messages have been updated )
 refNum (call) UpdateResFile
 dPtr (call) DisposDialog
 ELSE beep THEN
;

: fkey { | keycode -- }
 (call) frontwindow windowkind + w@ l_ext dup
 2 = swap 0< OR 0= IF 
 BEGIN 
 KeyEvent [‘] myEventRec (call) GetNextEvent UNTIL

 [‘] myEventRec message + @ $FF and -> keycode
 keycode ascii e = 
 IF edit.messages 
 ELSE
 keycode ascii 0 < keycode ascii 9 > OR
 IF beep ELSE keycode 48 - post.message
 THEN 
 THEN
 ELSE beep 
 THEN
;

( *** our standard glue routine *** )

CODE fkey.glue
 LINK A6,#-2048  ( 2K bytes of local Forth stack )
 MOVEM.L A0-A5/D0-D7,-(A7)( save registers )
 MOVE.L A6,A3    ( setup local loop return stack )
 SUBA.L #256,A3  ( starting 256 bytes below locals )
 ( no parameters are passed to the FKEY )
 JSR fkey ( call Forth routine )

 MOVEM.L (A7)+,A0-A5/D0-D7( restore registers )
 UNLK A6
 MOVE.L (A7)+,A0 ( return address )
 JMP  (A0)
END-CODE

header end

( install initial jump vector )
‘ fkey.glue ‘ start 2+ - ‘ start 2+ w!

( *** installation *** )

: make.fkey { | refNum namePtr -- }
 “ fkey.text” dup $create-res
 abort” You have to delete the old ‘fkey.text’ file first.”
 $open-res dup -> refNum call UseResFile 
[‘] start [‘] end over - call PtrToHand drop ( result code )
 “fkey 5 “ Mach2 FKEY” call AddResource
 refNum $close-res drop ( result code )
 0 “ fkey.text” 
 getvol ioVRefNum + w@ l_ext
 getfileinfo drop
 “qd15 “fkey “ fkey.text” setfileinfo
;
{2}
Listing 2: Rmaker file for the FKEY
* File fkr.R
Mach2 Fkey
FKEYQD15

Include Fkey.Text

Type DLOG
   ,2000
New Dialog
30 14 330 494
visible goAway
1
0
2000

Type DITL   
,2000
22

BtnItem
256 32 278 91
OK

StaticText
256 136 286 463  
Text FKEY © 1987 J. Langowski/MacTutor Written in Mach2™ Forth

EditText Disabled
8 32 24 464
Message 0

EditText Disabled
32 32 48 464
Message 1

EditText Disabled
56 32 72 464
Message 2

EditText Disabled
80 32 96 464
Message 3

EditText Disabled
104 32 120 464
Message 4

EditText Disabled
128 32 144 464
Message 5

EditText Disabled
152 32 168 464
Message 6

EditText Disabled
176 32 192 464
Message 7

EditText Disabled
200 32 216 464
Message 8

EditText Disabled
224 32 240 464
Message 9
 
StatText
8 8 24 28
0

StatText
32 8 48 28
1

StatText
56 8 72 28
2

StatText
80 8 96 28
3

StatText
104 8 120 28
4

StatText
128 8 144 28
5

StatText
152 8 168 28
6

StatText
176 8 192 28
7

StatText
200 8 216 28
8

StatText
224 8 240 28
9
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Coda 2.5.11 - One-window Web development...
Coda is a powerful Web editor that puts everything in one place. An editor. Terminal. CSS. Files. With Coda 2, we went beyond expectations. With loads of new, much-requested features, a few surprises... Read more
Bookends 12.5.7 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Access the power of Bookends directly from Mellel, Nisus Writer Pro, or MS Word (... Read more
Maya 2016 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
RapidWeaver 6.2.3 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
MacFamilyTree 7.5.2 - Create and explore...
MacFamilyTree gives genealogy a facelift: it's modern, interactive, incredibly fast, and easy to use. We're convinced that generations of chroniclers would have loved to trade in their genealogy... Read more
Paragraphs 1.0.1 - Writing tool just for...
Paragraphs is an app just for writers. It was built for one thing and one thing only: writing. It gives you everything you need to create brilliant prose and does away with the rest. Everything in... Read more
BlueStacks App Player 0.9.21 - Run Andro...
BlueStacks App Player lets you run your Android apps fast and fullscreen on your Mac. Version 0.9.21: Note: Now requires OS X 10.8 or later running on a 64-bit Intel processor. Initial stable... Read more
Tweetbot 2.0.2 - Popular Twitter client....
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
Apple iBooks Author 2.3 - Create and pub...
Apple iBooks Author helps you create and publish amazing Multi-Touch books for iPad. Now anyone can create stunning iBooks textbooks, cookbooks, history books, picture books, and more for iPad. All... Read more
NeoOffice 2014.12 - Mac-tailored, OpenOf...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more

Rage of Bahamut is Giving Almost All of...
The App Store isn't what it used to be back in 2012, so it's not unexpected to see some games changing their structures with the times. Now we can add Rage of Bahamut to that list with the recent announcement that the game is severely cutting back... | Read more »
Adventures of Pip (Games)
Adventures of Pip 1.0 Device: iOS iPhone Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** ONE WEEK ONLY — 66% OFF! *** “Adventures of Pip is a delightful little platformer full of charm, challenge and impeccable... | Read more »
Divide By Sheep - Tips, Tricks, and Stre...
Who would have thought splitting up sheep could be so involved? Anyone who’s played Divide by Sheep, that’s who! While we’re not about to give you complete solutions to everything (because that’s just cheating), we will happily give you some... | Read more »
NaturalMotion and Zynga Have Started Tea...
An official sequel to 2012's CSR Racing is officially on the way, with Zynga and NaturalMotion releasing a short teaser trailer to get everyone excited. Well, as excited as one can get from a trailer with no gameplay footage, anyway. [Read more] | Read more »
Grab a Friend and Pick up Overkill 3, Be...
Overkill 3 is a pretty enjoyable third-person shooter that was sort of begging for some online multiplayer. Fortunately the begging can stop, because its newest update has added an online co-op mode. [Read more] | Read more »
Scanner Pro's Newest Update Adds Au...
Scanner Pro is one of the most popular document scanning apps on iOS, thanks in no small part to its near-constant updates, I'm sure. Now we're up to update number six, and it adds some pretty handy new features. [Read more] | Read more »
Heroki (Games)
Heroki 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: CLEAR THE SKIES FOR A NEW HERO!The peaceful sky village of Levantia is in danger! The dastardly Dr. N. Forchin and his accomplice,... | Read more »
Wars of the Roses (Games)
Wars of the Roses 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
TapMon Battle (Games)
TapMon Battle 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: It's time to battle!Tap! Tap! Tap! Try tap a egg to hatch a Tapmon!Do a battle with another tapmons using your hatched tapmons! *... | Read more »
Alchemic Dungeons (Games)
Alchemic Dungeons 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: ### Release Event! ### 2.99$->0.99$ for limited time! ### Roguelike Role Playing Game! ### Alchemic Dungeons is roguelike... | Read more »

Price Scanner via MacPrices.net

15-inch 2.5GHz Retina MacBook Pro on sale for...
Amazon.com has the 15″ 2.5GHz Retina MacBook Pro on sale for $2274 including free shipping. Their price is $225 off MSRP, and it’s the lowest price available for this model. Read more
Logo Pop Free Vector Logo Design App For OS X...
128bit Technologies has released of Logo Pop Free 1.2 for Mac OS X, a vector based, full-fledged, logo design app available exclusively on the Mac App Store for the agreeable price of absolutely free... Read more
21-inch 1.4GHz iMac on sale for $999, save $1...
B&H Photo has new 21″ 1.4GHz iMac on sale for $999 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Best Buy has the 21″ 1.4GHz iMac on sale for $999.99 on their... Read more
16GB iPad mini 3 on sale for $339, save $60
B&H Photo has the 16GB iPad mini 3 WiFi on sale for $339 including free shipping plus NY tax only. Their price is $60 off MSRP. Read more
Save up to $40 on iPad Air 2, NY tax only, fr...
B&H Photo has iPad Air 2s on sale for up to $40 off MSRP including free shipping plus NY sales tax only: - 16GB iPad Air 2 WiFi: $489 $10 off - 64GB iPad Air 2 WiFi: $559 $40 off - 128GB iPad Air... Read more
Apple Releases OS X 10.10.4 With WIFi Fix, iO...
On Tuesday, Apple released final versions of OS X 10.10.4 and iOS 8.4, as well as updates for the Safari browser for OS X Yosemite, Mavericks, and Mountain Lion. The OS X 10.10.4 update focuses on... Read more
Dual-Band High-Gain Antennas for Home Wi-Fi N...
Linksys has announced what it claims are the first dual-band, omni-directional high-gain antennas for the consumer market. The new Linksys high-gain antennas available in a 2- and 4-pack (WRT004ANT... Read more
Apple refurbished 2014 15-inch Retina MacBook...
The Apple Store has Apple Certified Refurbished 2014 15″ 2.2GHz Retina MacBook Pros available for $1609, $390 off original MSRP. Apple’s one-year warranty is included, and shipping is free. They have... Read more
Clearance 2014 MacBook Airs available for up...
Adorama has 2014 MacBook Airs on sale for up to $301 off original MSRP including NY + NJ sales tax and free shipping: - 11″ 256GB MacBook Air: $798 $301 off original MSRP - 13″ 128GB MacBook Air: $... Read more
5K iMacs on sale for $100 off MSRP, free ship...
B&H Photo has the new 27″ 3.3GHz 5K iMac on sale for $1899.99 including free shipping plus NY tax only. Their price is $100 off MSRP. They have the 27″ 3.5GHz 5K iMac on sale for $2199, also $100... Read more

Jobs Board

*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Fulfillment Operations Execution Ana...
**Job Summary** The AMR Apple Fulfillment Operations Team is seeking a talented team player to drive the Apple Online Store (AOS) fulfillment performance to ensure a Read more
Localization Producer - *Apple* HR and Reta...
…project manager to support the Retail Globalization team. You will participate in Apple exponential inte ational growth and drive global project initiatives for the Read more
*Apple* Online Store UAT Lead - Apple (Unite...
**Job Summary** The Apple Online Store is a fast paced and ever evolving business environment. A UAT lead in this organization is able to have a direct impact on one of Read more
Senior Payments Security Manager - *Apple*...
**Job Summary** Apple , Inc. is looking for a highly motivated, innovative and hands-on senior payments security manager to join the Apple Pay security team. You will Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.