![](/file/12652/www.mactech.com.tar/www.mactech.com/sites/all/themes/custom_front/images/you_are_here_red.gif)
![](/file/12652/www.mactech.com.tar/www.mactech.com/sites/default/files/beta-site.gif)
|
Volume Number: | 6 | |
Issue Number: | 5 | |
Column Tag: | Assembly Lab |
Volume FKEY--Dialog Lists in Memory
By John Holder, Eureka, CA
What’s the deal here anyway?
My first article for MacTutor™ showed you how to create an Fkey that used its own menus and acted just like an application (refer to MacTutor™ Vol.4 No.6). This article will show you how to create a very simple FKEY using a dialog to allow you to change the volume level of the Macintosh speaker. It also shows how to create a Dialog ITem List (the data normally stored in a DITL resource) in memory so your FKEY doesn’t need any other resources.
How do I use this thing?
This Fkey was created with the Macintosh 68000 Development System. All applications are on a disk titled ‘MDS1’ and all .D files are on a disk titled ‘MDS2’. First assemble the file ‘Volume-Fkey.Asm’, then run the linker on the file ‘ Volume-Fkey.Link’, and finally run RMaker on the file ‘ Volume-Fkey.R’. You will now have an FKEY ready to put into your System file!
Volume-Fkey, How it Works
When the Fkey starts, there is a short jump over its header, then the applications current port and all registers are saved, next it brings up the standard arrow cursor with _InitCursor. When we’ve successfully allocated storage for the FKEYs globals and room for the dialog item list handle, we get the current value of the speakers volume by getting the low 3 bits of the global variable ‘sdVolume’ (a byte) and putting the value in our own global CurrentVol(A4).
Now we jump to a routine that puts the data (defined as contants at the end of the code) into our item list handle. Now the dialog is created and the handle to our item list is passed to the _NewDialog routine which draws the dialog and all of the items in the list. Then we want to set the appropriate radio button depending on the current volume level. We do this by adding 3 (the item number of the first radio button) to the current volume level to determine which radio button to hilight and call _SetCtlValue to set it. Now, it’s onward to the main loop!
The Main Loop
Since we’re using a dialog we can let _ModalDialog handle all the events for us. All we have to do is wait for _ModalDialog to return an item number and jump to an appropriate routine to handle it. If the Enter or Return key is pushed _ModalDialog returns item number 1, which is the default button in a dialog and in this case is the Quit button.
A click in a radio button
We’ve spotted a click on one of the radio buttons! So we put the item hit in register D7 for safekeeping and jump to a routine to handle changing the volume. We clear all the radio buttons (makes it a bit easier than remembering what the last hilighted button was, guess I’m kind of lazy) and then hilight the one clicked on. Now we take it’s item number and subtract 3 from it to figure the new volume level.
The next step is to change the low order 3 bits of three different variables which the Mac stores the sound level in (each one is a byte) without disturbing any other data in the other bits of the byte. These are; ‘sdVolume’, ‘SPVolCtl’ and the VIA data register A (you get at this by getting the base address of the VIA and adding the offset vBufA to it to access the byte containing the sound volume level, see Inside Mac, Vol. III-21 & III-39).
When those are set we call _WriteParam to write the new volume level to the clock chip, beep the speaker and return to the main loop!
A click in the Info button
When the mouse is clicked in the “Info” button, we change the dialogs font to 9 point Monaco with _TextFont and _TextSize. Now we set up the stack to call _TextBox to display the Info text (which is defined at the end of the code between ‘AboutTextBegin’ & ‘AboutTextEnd’ which makes it very easy to add or change any message you’d like to have displayed when the Info button is clicked). _TextBox calls _EraseRect which temporarily clears the dialogs window before displaying the text. We simply wait for a button or key down event and erase the window, reset the dialogs font and call _DrawDialog to redraw all the controls in the dialog and return to the main loop.
Doing the Quit
When an Fkey quits it must dispose of any memory it created. After the dialog is disposed of with a call to _DisposDialog (which in turn releases the memory we allocated for the item list), the memory we allocated for the globals is released, all events are flushed, the applications current port and registers are restored, and a return from subroutine RTS returns command to the application!
The Dialog Item List
I’ve defined my Item List at the end of the source file as constants. Basically there’s a word at the beginning of the item list which tells how many items are in the list (-1). After that, each item in the list is defined, the first long word is a space reserved for the controls handle when it’s created, the next 4 words are the items rectangle in local coordinates, then a byte defining the control type, a byte (which must be even) which tells how many bytes are in the last field (which is the Title of the control).
When creating your own item list you must make sure the Title of each control has an even amount of bytes (each of mine is four bytes long except the last item, the Volume-Fkey string) and that you make sure to allocate enough memory for your item list by setting the BytesInItemList equate near the beginning of the code. For more information on the format of an Item List refer to Inside Mac Vol. I-427.
Final Comments...
If there’s anything I haven’t explained fully just take a look at the source code as I’ve commented it quite well. You should always take the time to comment your code AS you’re coding! You wouldn’t want to take a look at your code later and ask yourself what the heck you were doing would you? Well, that’s it, I hope you’ve learned something useful from this article. See you next time...
;File: Volume-Fkey.Asm ;------------------------------------------------ ;An FKEY that lets you change the speakers volume ;© 1989 by John Holder for MacTutor ;By John Holder Thu May 4, 1989 ;------------------------------------------------ ;The purpose of this Fkey is to show how to set-up & use ;an item list in memory for a dialog (instead of using a ;DITL resource) and to show how to check and set the Macs ;speaker volume INCLUDETraps.D Include ToolEqu.D; Use ToolBox equates IncludeSysEqu.D ; Use System equates ;some useful macros MACRO MakePointerHowManyBytes,StorageRegister = MOVE.L #{HowManyBytes},D0 _NewPtr,CLEAR MOVE.L A0,{StorageRegister} | MACRO MakeHandle HowManyBytes,StorageRegister = MOVE.L #{HowManyBytes},D0 _NewHandle,CLEAR MOVE.L A0,{StorageRegister} | MACRO SaveRegs = MOVEM.LA0-A4/D0-D7,-(SP) | MACRO RestoreRegs= MOVEM.L(SP)+,A0-A4/D0-D7 | MACRO beep= MOVE.W #10,-(SP) _SysBeep | ;------------------------------------------------ ;All equates go here ;------------------------------------------------ ;these are offsets into our global storage. ;(a non-relocatable block we created pointed to by A4) ;------------------------------------------------ EventBlockequ 0 what equ 0 ; Event number message equ 2 ; Additional information when equ 6 ; Time event was posted where equ 10 ; Mouse coordinates modify equ 14 ; State of keys and button TheWindow equ 16; var used by _DialogSelect windowpointer equ 20; Dialog ptr ItemListHandle equ 24; Item List handle ItemHit equ 28 ; word CurrentVolequ 30; current Volume (byte) padding equ 31 ; next byte (unused) DispRectequ 32 ItemNumberequ 40 ItemHandleequ 42 ItemTypeequ 46 MemNeeded equ 100 ;how much memory needed ;for globals mDownMask equ 2 keyDownMask equ 8 true equ $0100 false equ 0 nilequ 0 ;Buttons used in dialog QuitButtonequ 1 InfoButtonequ 2 ZeroBut equ 3 OneBut equ 4 TwoBut equ 5 ThreeButequ 6 FourBut equ 7 FiveBut equ 8 SixBut equ 9 SevenButequ 10 BytesInItemList equ 300 ;how many bytes we want ;allocated for the dialog’s ;item list SysParamequ $1F8 ;location of copy of Parameter ;RAM (PRAM) settings (20 bytes) ;used by _WriteParam SPVolCtlequ $208 ;location of the speaker vol. ;setting in the copy of PRAM ;settings VIAequ $1D4;contains address of the ;VIA buffer vBufA EQU $1E00;Offset to Buffer A (of the ; VIA) (for the sound chip) ;------------------------------------------------ ;The start of the Fkey ;------------------------------------------------ JumpIt BRA.S Start ;Jump the FKEY header info DC.W 0 DC.B ‘FKEY’ DC.W 7 ;(FKEYs res id#) DC.W 0 Start SaveRegs ;save current port SUBQ #4,SP MOVE.L SP,-(SP) _GetPort _InitCursor ;allocate storage for our globals MakePointerMemNeeded,A4 cmp.l #0,A4 ;if returned ptr is not bne.s Pointer_Is_Fine ;zero it was allocated ok ;not enough mem if it gets here, so beep & quit bsr Theres_Been_an_Error bra No_Mem_Must_Quit Pointer_Is_Fine ;will get here if pointer was allocated! ;set up storage for our dialogs Item List MakeHandle BytesInItemList,ItemListHandle(A4) cmp.l #0,ItemListHandle(A4) ;if returned handle bne.s Handle_Is_Fine ; is not zero it was ;allocated ok ;not enough mem if it gets here, so beep, ;release global storage we just allocated & quit bsr Theres_Been_an_Error bra No_Handle_Jump Handle_Is_Fine ;will get here if handle was allocated! ;save current speaker volume level ;speaker volume level is store in low ;3 bits of global var sdVolume move.b sdVolume,D0 and.b #$07,D0 ;clear all but low 3 bits move.b D0,CurrentVol(A4) bsr ShowDialog ;------------------------------------------------ ;The Main loop ;------------------------------------------------ MainLoop ;let _ModalDialog handle all events clr.l -(sp) ;filter proc pea ItemHit(A4);returns dialog item hit _ModalDialog ;which item was clicked? cmp #QuitButton,ItemHit(A4) beq QuitRoutine cmp #InfoButton,ItemHit(A4) beq DoAbout ;if it wasn’t on of the two buttons ;check for click in the radio buttons ;if ItemHit(A4) is < the first radio ;button or > the last one we don’t ;handle it cmp #ZeroBut,ItemHit(A4) blt MainLoop cmp #SevenBut,ItemHit(A4) bgt MainLoop move ItemHit(A4),D7 bsr ChangeAndBeep bra MainLoop ;back to the Main loop ;------------------------------------------------ ;Turn on button selected and beep ;------------------------------------------------ ChangeAndBeep saveregs ;it was a click in a radio button ;first, unhilite all the radio buttons! bsr Clear_Radio_Buttons ;now turn on the one that was clicked on! move.l windowpointer(A4),-(SP) move D7,-(sp) pea ItemType(A4) pea ItemHandle(A4) pea DispRect(A4) _GetDItem move.l ItemHandle(A4),-(sp) move #1,-(sp) _SetCtlValue ;calculate new volume setting by which button was ;clicked. ;button clicked (3-10) - first button (3) = new ;volume setting move D7,D2 sub #ZeroBut,D7 and.b #$07,D7 ;clears all but low 3 bits ;set the sdVolume global var to sound ;level chosen! move D7,D2 ;put new setting into D2 move.b sdVolume,D1;get current value and.b #$F8,D1 ;clears low 3 bits (leaves ;the rest of the sdVolume ;bits unchanged) or.b D1,D2 ;combine the two move.b D2,sdVolume;set the global to new value ;save new speaker volume level move.b sdVolume,D0 and.b #$07,D0 ;clear all but low 3 bits move.b D0,CurrentVol(A4) ;set the SPVolCtl (part of Parameter RAM vars kept ;in low memory globals) move D7,D2 ;put new setting into D2 move.b SPVolCtl,D1;get current value and.b #$F8,D1 ;clears low 3 bits (leaves ;the rest of the SPVolCtl ;bits unchanged) or.b D1,D2 ;combine the two move.b D2,SPVolCtl;set the global to new value ;last, set the VIA Buffer A global var ;to sound level chosen (this is the sound ;chip buffer A) move D7,D2 ;put new setting into D2 move.l VIA,A0 ;pointer to Vbase move.b vBufA(A0),D1 ;get current value and.b #$F8,D1 ;clears low 3 bits (leaves ;the rest of the ;bits unchanged) or.b D2,D1 ;combine the two move.l VIA,A0 ;pointer to Vbase move.b D1,vBufA(A0) ;set the global to new value ;now change parameter RAM ;Saves settings in clock chip lea SysParam,A0 move.l minusOne,D0 _WriteParam beep ;beep to hear new setting restoreregs rts ;------------------------------------------------ ;Do about (info button was pushed) ;------------------------------------------------ DoAbout saveregs ;set to Monaco 9pt MOVE.W #Monaco,-(SP) _TextFont MOVE.W #9,-(SP) _TextSize ;use _TextBox to show About info pea AboutTextBegin MOVE.L #AboutTextEnd-AboutTextBegin,-(SP) PEA TextRect MOVE.W #0,-(SP) ;left justification _TextBox bsr Wait_For_Event ;wait for mouse or ;key click ;erase About text pea TextRect _EraseRect ;restore normal text attributes for the dialog MOVE.W #0,-(SP) ;0 = systemFont _TextFont MOVE.W #12,-(SP);12 point _TextSize ;redraw the dialog to show all controls move.l windowpointer(A4),-(sp) _DrawDialog restoreregs BRA MainLoop ;------------------------------------------------ ;Quit, rel6.5 Volume FKEY ;-------------------------------------------- QuitRoutine ;This will also dispose of the handle ;we created for the item list so we dont ;have to MOVE.L windowpointer(A4),-(SP) _DisposDialog No_Handle_Jump move.l A4,A0 _DisposPtr No_Mem_Must_Quit MOVE.L #$0000FFFF,D0 _FlushEvents ;flush of all events _SetPort ;restore port restoreregs rts Theres_Been_an_Error ;will jump here if space ;couldn’t be allocated! beep Rts ;------------------------------------------------ ;Set up the dialog ;------------------------------------------------ ShowDialog saveregs bsr SetUpItmList ;create the dialog CLR.L -(SP) ;For ptr clr.l -(SP) ;dialog storage pea WindowRect ;rect of dialog clr.l -(sp) ;title MOVE #true,-(SP);vis MOVE.W #dboxproc,-(SP) MOVE.L #-1,-(SP);behind wind ptr MOVE #false,-(SP) ;goaway clr.l -(sp) ;refcon move.l ItemListHandle(A4),-(sp) ;handle to item list _NewDialog MOVE.L (SP),windowpointer(A4) ;leave ptr on stack _SetPort bsr SetUpControl ;show current vol. level restoreregs rts ;------------------------------------------------ ;Set up our item list ;------------------------------------------------ SetUpItmList ;blockmove our item list into space we ;allocated for it at the beginning move.l ItemListHandle(A4),A0 _HLock ;dont want it ;moving! lea ItmList,A0 ;from ptr move.l ItemListHandle(A4),A1 move.l (A1),A1 move.l #BytesInItemList,D0 ;lgth of data _BlockMove move.l ItemListHandle(A4),A0 ;unlock it _HUnLock rts ;------------------------------------------------ ;Turn on button (depending on the current volume) ;------------------------------------------------ SetUpControl ;depending on the value of sdVolume, turn on the appropriate ;radio button! saveregs clr D6 move.b CurrentVol(A4),D6 add #ZeroBut,D6;make volume level ;correspond to a button ;in the dialog move.l windowpointer(A4),-(SP) move D6,-(sp) pea ItemType(A4) pea ItemHandle(A4) pea DispRect(A4) _GetDItem ;turn on the button move.l ItemHandle(A4),-(sp) move #1,-(sp) _SetCtlValue restoreregs rts ;------------------------------------------------ ;Wait for key or mouse press ;------------------------------------------------ Wait_For_Event LINK A6,#-evtBlkSize Here LEA -evtBlkSize(A6),A0 MOVEQ #mDownMask!KeyDownMask,D0 _GetOSEvent BEQ M_Down BRA Here;keep looping until mouse press! M_Down UNLK A6 rts ;------------------------------------------------ ;Clear all radio buttons ;------------------------------------------------ Clear_Radio_Buttons ;Unhilite all the radio buttons! saveregs move #7,D7 ;how many times to loop ;(8 buttons -1 for dbra) move #ZeroBut,D6;button to clear Clear_Loop move.l windowpointer(A4),-(SP) move D6,-(sp) pea ItemType(A4) pea ItemHandle(A4) pea DispRect(A4) _GetDItem move.l ItemHandle(A4),-(sp) move #0,-(sp) _SetCtlValue add #1,D6 ;inc. dialog item counter dbra D7,Clear_Loop restoreregs rts ;------------------------------------------------ ;Constants ;------------------------------------------------ WindowRectDC.W 105,145,265,365 TextRectDC.W5,5,150,215 ;for About info ;Item list of our dialog (this data ;get copied into a handle ItmList dc10;number of items in list - 1 dc.l 0 ;place for handle dc130,40,150,95 ;item rect dc.b btnCtrl+4 ;Item type (Button Ctrl) dc.b 4 ;length of following data dc.b ‘Quit’;Title dc.l 0 dc130,125,150,180 dc.b btnCtrl+4 dc.b 4 dc.b ‘Info’ dc.l 0 dc30,30,45,70 dc.b radCtrl+4 ;(Radio Button Ctrl) dc.b 4 dc.b ‘0 ‘; 0 + 3 spaces (same with ;all radio buttons below) dc.l 0 dc50,30,65,70 dc.b radCtrl+4 dc.b 4 dc.b ‘1 ‘ dc.l 0 dc70,30,85,70 dc.b radCtrl+4 dc.b 4 dc.b ‘2 ‘ dc.l 0 dc90,30,105,70 dc.b radCtrl+4 dc.b 4 dc.b ‘3 ‘ dc.l 0 dc30,150,45,190 dc.b radCtrl+4 dc.b 4 dc.b ‘4 ‘ dc.l 0 dc50,150,65,190 dc.b radCtrl+4 dc.b 4 dc.b ‘5 ‘ dc.l 0 dc70,150,85,190 dc.b radCtrl+4 dc.b 4 dc.b ‘6 ‘ dc.l 0 dc90,150,105,190 dc.b radCtrl+4 dc.b 4 dc.b ‘7 ‘ dc.l 0 dc5,62,15,170 dc.b statText dc.b 12 dc.b ‘Volume-Fkey ‘ ; Volume-Fkey + 1 space EndItmList AboutTextBegin dc.b ‘ Volume-Fkey (1.0)’,$0D dc.b ‘ (c) 1989 by John Holder’,$0D dc.b ‘ for MacTutor™’,$0D,$0D dc.b ‘ This Fkey lets you change the speaker volume. ‘ dc.b ‘Click on a button to set the volume.’ .ALIGN 2 AboutTextEnd END * File: Volume-Fkey.R * RMaker source file * for Volume-Fkey FKEY MDS1:Volume-Fkey.Fkey FKEYSPFK TYPE FKEY = PROC Volume-Fkey,7 MDS2:Volume-Fkey.Code ; File: Volume-Fkey.Link ; Linker source file ; for Volume-Fkey /Output Volume-Fkey.Code /Type ‘TEMP’ Volume-Fkey $
![](/file/12652/www.mactech.com.tar/www.mactech.com/sites/all/themes/custom_front/img/search_text.gif)
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine