******************************************************************************* * * KeyMenu-Handler.asm V1.03 02 Mar 1991 * * * * This program is loaded by 'KeyMenu' and stays resident in the * system until the user runs KeyMenu with the 'QUIT' option. * * * * Modification History: * * Date By Modification * -------- -------------------- -------------------------------------- * 09/09/89 Ken Lowther Initial release, V1.01 * * 09/13/89 Ken Lowther V1.02 - added qualifier keys to move * mouse pointer to first/last item. * * 09/24/89 Ken Lowther V1.02 - corrected positioning of mouse * pointer on menus. The pointer was being * positioned 1 pixel to the left. This * really only mattered when the menu is * 1 pixel wide. * * 09/30/89 Ken Lowther V1.02 - Keymenu no longer creates a * process for this module. Changed 'main' * to set the DOS return code and return * in case this module gets 'execute'ed. * * 10/03/89 Ken Lowther V1.02 - Changed to ignore the 1st * occurance of a 'repeated' key. This * is to fix a problem that occurs when * there are more than 2 bitplanes in the * screen. * * 03/02/91 Ken Lowther V1.03 - Modified to use PointerPos * events rather than RawMouse events to * position intuition's pointer. This * allows Keymenu to co-exist with most * mouse accelerators. * * 03/02/91 Ken Lowther V1.03 - Re-installed intuition pointer * blanking option. * ******************************************************************************* nolist include "macros.i" include "exec/types.i" include "exec/strings.i" include "exec/nodes.i" include "exec/ports.i" include "exec/execbase.i" include "exec/ables.i" include "exec/interrupts.i" include "exec/memory.i" include "devices/inputevent.i" include "intuition/intuition.i" include "libraries/dos.i" include "libraries/dosextens.i" include "keymenu-handler.i" list nomlist ******************************************************************************* * * * Displacements into Select routine. * * * ******************************************************************************* s_top equ si_top-si_jmp-2 s_adjacent_top equ si_adjacent_top-si_jmp-2 s_adjacent_up equ si_adjacent_up-si_jmp-2 s_up equ si_up-si_jmp-2 s_adjacent_right equ si_adjacent_right-si_jmp-2 s_right equ si_right-si_jmp-2 s_leftmost equ si_leftmost-si_jmp-2 s_adjacent_down equ si_adjacent_down-si_jmp-2 s_bottom equ si_bottom-si_jmp-2 s_adjacent_left equ si_adjacent_left-si_jmp-2 s_down equ si_down-si_jmp-2 s_left equ si_left-si_jmp-2 s_rightmost equ si_rightmost-si_jmp-2 gbl equr a4 ; handler global area cseg near code ******************************************************************************* * * * main * * * * This is the main routine of KeyMenu-Handler. It is where execution * * begins. Here we perform the following functions: * * 1) Initialize program. This consists of determining what task we * * are and finding the public message port that the KeyMenu * * program created for us. If the port doesn't exist or if * * another task already owns it, we just exit (this can happen if * * the user somehow manages to run this program instead of * * KeyMenu). The global area behind the message port, created by * * Keymenu, is updated with our task address, the signal number * * to use to send messages to us, the address of our input * * handler routine and the version number of this program. We * * then signal KeyMenu that we are initialized. * * 2) Wait for one of two events to occur. Either a message has been * * directed to us via the public message port or KeyMenu has * * signalled us to stop. Process the event as appropriate. * * 3) Step 2, above, is repeated until our 'active' flag is reset. * * This occurs when, at our request, the input_handler sends a * * message to us indicating it is ready to stop. We then cleanup * * any resources we have allocated and return to AmigaDOS. * * * * Input Registers: * * None. * * * * Output Registers: * * None. * * * ******************************************************************************* main movem.l mainregs,-(sp) ; save entry registers *-----------------------------------------------------------------------------* * do initialization * *-----------------------------------------------------------------------------* move.l AbsExecBase,a6 ; setup base for exec.library sub.l a1,a1 ; set to find our task Call FindTask ; get pointer to our task move.l d0,a2 ; get task address clr.l pr_ConsoleTask(a2) ; clear console handler pointer lea myport(pc),a1 ; pointer to port name Call FindPort ; go find our port tst.l d0 ; does it exist ? beq main060 ; no, must have it, get out move.l d0,gbl ; save pointer to our world tst.l MP_SIGTASK(gbl) ; is a task already there ? bne main060 ; yes, branch *-----------------------------------------------------------------------------* * everything seems ok, update our global area and signal KeyMenu to * * go ahead and add our input_handler routine to the input.device * *-----------------------------------------------------------------------------* moveq.l #-1,d0 Call AllocSignal ; get a signal for our task move.b d0,MP_SIGBIT(gbl) ; save the signal number move.l a2,MP_SIGTASK(gbl) ; make our task the one to signal move.l a2,gb_handtask(gbl) lea input_handler(pc),a1 ; get addr of input handler code move.l a1,gb_handler+IS_CODE(gbl) ; put it in interrupt struct jsr dosignal ; go signal companion task moveq.l #1,d4 ; set active flag *-----------------------------------------------------------------------------* * if we are still active, wait for something to happen * *-----------------------------------------------------------------------------* main010 tst.w d4 ; are we still active ? beq main050 ; no, go clean things up clr.l d1 ; clear work register move.b MP_SIGBIT(gbl),d1 ; get signal bit number bset.l d1,d0 ; create signal mask bset.l #SIGBREAKB_CTRL_C,d0 ; set break bit Call Wait ; wait for something to happen *-----------------------------------------------------------------------------* * An event occurred! Determine if KeyMenu signalled 'CTRL C' * * telling us to stop. If not, there must be a message waiting on * * the message port. * *-----------------------------------------------------------------------------* btst.l #SIGBREAKB_CTRL_C,d0 ; did user request us to stop ? beq main015 ; no, branch bset.b #FLAGB_Stop_requested,gb_flags(gbl) ; set stop requested ; this tells the input handler to ; stop the next time it is entered bra main010 ; go wait for input handler to stop *-----------------------------------------------------------------------------* * get a message from the message port and determine what it is * *-----------------------------------------------------------------------------* main015 move.l gbl,a0 ; get address of message port Call GetMsg ; get any message placed there tst.l d0 ; was there a message queued ? beq main010 ; no, branch move.l d0,a2 ; save message address cmp.w #req_stopped,LN_NAME(a2) ; stop message ? bne main020 ; no, branch *-----------------------------------------------------------------------------* * A 'stop' message was received from the input handler. Clear our * * 'active' flag. * *-----------------------------------------------------------------------------* clr.l d4 ; yes, clear active flag main020 cmp.w #req_clearpointer,LN_NAME(a2) ; clear pointer request ? bne main030 ; no, branch *-----------------------------------------------------------------------------* * A 'clearpointer' request was received from the input handler. * * This causes us to reset the intuition pointer to its previous * * condition prior to our blanking it. * *-----------------------------------------------------------------------------* tst.l gb_Pointer(gbl) ; is any pointer info saved ? beq main025 ; no, branch move.l gb_window(gbl),a0 ; yes, setup to do 'SetPointer' move.l gb_Pointer(gbl),a1 ; this will restore the window's move.b gb_PtrHeight(gbl),d0 ; custom pointer ext.w d0 ext.l d0 move.b gb_PtrWidth(gbl),d1 ext.w d1 ext.l d1 move.b gb_XOffset(gbl),d2 ext.w d2 ext.l d2 move.b gb_YOffset(gbl),d3 ext.w d3 ext.l d3 Call SetPointer,gb_IBase(gbl) ; restore the custom pointer clr.l gb_Pointer(gbl) ; clear pointer info bra main030 main025 move.l gb_window(gbl),a0 Call ClearPointer,gb_IBase(gbl) ; reset back to intuition's ; pointer main030 cmp.w #req_setpointer,LN_NAME(a2) ; set pointer request ? bne main040 ; no, branch *-----------------------------------------------------------------------------* * A 'setpointer' request was received from the input handler. This * * causes us to save info about the current custom pointer, if any, * * and call 'SetPointer' using our own 'blank' pointer. This removes * * the pointer from the user's view during menu operations. * *-----------------------------------------------------------------------------* move.l gb_window(gbl),a0 tst.l wd_Pointer(a0) ; is there a custom pointer ? beq main035 ; no, branch move.l wd_Pointer(a0),gb_Pointer(gbl) ; save custom pointer info move.b wd_PtrHeight(a0),gb_PtrHeight(gbl) move.b wd_PtrWidth(a0),gb_PtrWidth(gbl) move.b wd_XOffset(a0),gb_XOffset(gbl) move.b wd_YOffset(a0),gb_YOffset(gbl) main035 move.l gb_blank_ptr(gbl),a1 ; setup to call 'SetPointer' moveq.l #-1,d0 moveq.l #-1,d1 clr.l d2 clr.l d3 Call SetPointer,gb_IBase(gbl) *-----------------------------------------------------------------------------* * free the message we received and loop to see if there is more * *-----------------------------------------------------------------------------* main040 clr.l d0 move.l a2,a1 ; setup addr of block to free move.w MN_LENGTH(a1),d0 ; setup length of block to free Call FreeMem ; go free it bra main015 ; loop for next message myport portname *-----------------------------------------------------------------------------* * We are no longer active, cleanup after ourselves and get out * *-----------------------------------------------------------------------------* main050 move.l gbl,a0 ; get address of message port Call GetMsg ; get any message placed there tst.l d0 ; was there a message queued ? beq main055 ; no, branch move.l d0,a1 ; setup to free the block clr.l d0 move.w MN_LENGTH(a1),d0 ; setup length of block to free Call FreeMem ; go free it bra main050 ; loop for next message main055 clr.l d0 move.b MP_SIGBIT(gbl),d0 ; get signal number Call FreeSignal ; go free it Forbid jsr dosignal ; go signal companion task main060 movem.l (sp)+,mainregs ; restore entry registers rts ; return to AmigaDOS mainregs reg d1-d7/a0-a6 ******************************************************************************* * * * dosignal * * * * Send a signal to our companion task (should be KeyMenu). * * * * Input Registers: * * a4 - global work area * * * * Output Registers: * * None. * * * ******************************************************************************* dosignal clr.l d1 ; clear work register move.b gb_tasksignum(gbl),d1 ; get keymenu task signal number bset.l d1,d0 ; create signal mask move.l gb_task(gbl),a1 ; get task to signal Call Signal ; signal the task that we are ready rts ****************************************************************************** * * * input_handler * * * * This routine is added to the input.device's list of handlers by the * * KeyMenu program. It is called whenever an input event, such as a * * keyboard press or mouse movement, occurs. In general, the input event * * chain is scanned to see if the user has pressed any one of the * * various keys that we care about. If so, the input event representing * * that keypress is replaced with a mouse event(s) to accomplish * * KeyMenu's purpose. Note that the memory associated with event(s) that * * are removed from the list actually belongs to the creator of that * * event. It is the event creator's responsibility to free this memory. * * See the RKM for more info about input handlers and the input.device * * * * Input Registers: * * a0 - input event chain, a forward reference linked list with the * * last event in the chain containing a 'NULL' reference. * * a1 - global work area * * * * Output Registers: * * d0 - new input event chain * * * ******************************************************************************* input_handler laste equr a1 ; last event handled in chain ev equr a2 ; original event passed to us ep equr a3 ; current event pointer movem.l ihregs,-(sp) ; save registers move.l a1,gbl ; setup pointer to our world move.l a0,ev ; save pointer to input event chain *-----------------------------------------------------------------------------* * If 'stop' has been posted, check to see if there is currently a * * menu active. If so, wait for the user to get out of it otherwise * * send a 'stop' message (actually means 'ready to stop') to the * * KeyMenu-Handler process. * *-----------------------------------------------------------------------------* btst.b #FLAGB_Stop_requested,gb_flags(gbl) ; stop requested ? beq ih010 ; no, branch btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu currently active ? bne ih010 ; yes, branch btst.b #FLAGB_Stopped,gb_flags(gbl) ; stop already been posted ? bne ih010 ; yes, branch moveq.l #req_stopped,d0 ; set type fo request to send jsr sendrequest ; go send it bset.b #FLAGB_Stopped,gb_flags(gbl) ; indicate stop has been posted *-----------------------------------------------------------------------------* * Begin stepping through the input event chain * *-----------------------------------------------------------------------------* ih010 FORBID ; don't let anyone mess with events sub.l laste,laste ; clear last event register move.l ev,ep ; setup event work register bclr.b #FLAGB_Events_inserted,gb_flags(gbl) ; clear inserted flag bra ih040 ; go see if an event exists ih015 cmp.b #IECLASS_RAWKEY,ie_Class(ep) ; Raw key event ? bne ih025 ; no, branch *-----------------------------------------------------------------------------* * This is a RAWKEY event (keypress/keyrelease). * *-----------------------------------------------------------------------------* jsr Check_RawKey_Event ; go look at this one beq ih030 ; do we keep it ? yes, branch move.l laste,d0 ; was there a previous event ? bne ih020 ; yes, branch move.l ie_NextEvent(ep),ev ; drop the event bra ih035 ih020 move.l ie_NextEvent(ep),ie_NextEvent(laste) bra ih035 ; loop *-----------------------------------------------------------------------------* * Here we look for a 'MENUDOWN' event. If this occurs while we have * * a menu active, it indicates that the user pressed the right mouse * * button intending to take over menu selection with the mouse. * *-----------------------------------------------------------------------------* ih025 cmp.b #IECLASS_RAWMOUSE,ie_Class(ep) ; is this a raw mouse event ? bne ih030 ; no, branch cmp.w #MENUDOWN,ie_Code(ep) ; is it a menu down event ? bne ih030 ; no, branch btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu in progress ? beq ih030 ; no, branch bclr.b #FLAGB_MActive,gb_flags(gbl) ; give control of menu to mouse moveq.l #req_clearpointer,d0 jsr sendrequest ; go reset intuition pointer *-----------------------------------------------------------------------------* * Now we look to see if we inserted any events in the chain. If so, * * we must get out. This is because we only have a fixed number of * * input event areas allocated (3) and they can be used only once * * per invocation of the handler. This could be a potential problem * * in that we could miss events that we care about (since we don't * * look at the remaining events in the event chain). However, this * * is nothing that would cause harm to the system. It would just * * appear to the user as though a keypress intended to cause a menu * * operation didn't take. This is better than incuring the overhead * * and buffer management problems associated with dynamically * * allocating input events. * *-----------------------------------------------------------------------------* ih030 move.l ep,laste ; save this event ih035 btst.b #FLAGB_Events_inserted,gb_flags(gbl) ; were events inserted? bne ih045 ; yes, branch *-----------------------------------------------------------------------------* * Setup to process the next event if one exists, otherwise get out * *-----------------------------------------------------------------------------* move.l ie_NextEvent(ep),ep ; get next event ih040 move.l ep,d0 ; set cc bne ih015 ; go check it ih045 PERMIT move.l ev,d0 ; pass event on movem.l (sp)+,ihregs ; restore registers rts ; return to input device ihregs reg a0/a1/a2/a3/a4/a6 ******************************************************************************* * * * sendrequest * * * * This routine is called by the input handler when it wishes to send a * * request message to the KeyMenu-Handler process. There are currently * * three kinds of messages that may be sent: * * 1) req_setpointer, to blank the intuition pointer during menu * * operations. * * 2) req_clearpointer, to restore the intuition pointer when menu * * operations are finished. * * 3) req_stopped, to signal that the handler is ready to stop. * * Sendrequest is always called regardless of the setting of the hide * * intuition pointer option. This is where we determine whether or not * * to actually send the request. * * * * Input Registers: * * d0 - type of request to be sent * * a4 - global work area * * * * Output Registers: * * none. * * * ******************************************************************************* sendrequest movem.l sendreqregs,-(sp) ; save entry registers btst.b #FLAGB_Blank_pointer,gb_flags(gbl) ; blank pointer option on ? bne sendreq010 ; yes, branch cmp.w #req_stopped,d0 ; is this a 'stopped' request ? bne sendreq020 ; no, branch sendreq010 move.l d0,d2 ; save request type move.l #MEMF_CLEAR+MEMF_PUBLIC,d1 ; set attributes move.l #MN_SIZE,d0 ; set size of block Call AllocMem ; go allocate a block tst.l d0 ; was a block given to us ? beq sendreq020 ; no, branch move.l d0,a1 ; yes, save pointer to block move.w d2,LN_NAME(a1) ; format message clr.l MN_REPLYPORT(a1) move.w #MN_SIZE,MN_LENGTH(a1) move.l gbl,a0 Call PutMsg ; write it to the port sendreq020 movem.l (sp)+,sendreqregs ; restore registers rts ; return to caller sendreqregs reg a0/a1/d0-d2 ******************************************************************************* * * * Check_RawKey_Event * * * * This routine checks each RAWKEY event (keypress/keyrelease) to see if * * it is one that we are interested in. If it is, the event that is * * passed to us is replaced with events to do the appropriate KeyMenu * * function. Events that have no meaning for us are passed back to the * * caller indicating that they should remain in the input event chain. * * * * Input Registers: * * a3 - rawkey event to be checked * * a4 - global work area * * * * Output Registers: * * d0 - 0=discard the event, 1=keep the event * * * ******************************************************************************* Check_RawKey_Event movem.l creregs,-(sp) ; save registers clr.l d0 btst.b #IEQUALIFIER_REPEAT_R,ie_Qualifier(a3) ; is it a repeat ? beq cre003 ; no, branch btst.b #FLAGB_Repeat_skipped,gb_flags(gbl) ; have we skipped one ? bne cre004 ; yes, branch bset.b #FLAGB_Repeat_skipped,gb_flags(gbl) ; indicate repeat skipped bra cre_remove ; remove it from the input chain cre003 bclr.b #FLAGB_Repeat_skipped,gb_flags(gbl) ; clear repeat skipped cre004 btst.b #FLAGB_MActive,gb_flags(gbl) ; is a menu currently active ? bne cre035 ; yes, branch *-----------------------------------------------------------------------------* * A menu is not currently active, check to see if one is being * * activated (keypress of the configured activation key). * *-----------------------------------------------------------------------------* move.b gb_AKey(gbl),d0 ; get configured activation key code cmp.w ie_Code(a3),d0 ; Menu Activate Key ? bne cre010 ; no, branch *-----------------------------------------------------------------------------* * The user pressed the menu activation key, set a flag indicating * * that fact and wait to see if the key is released without pressing * * any other keys. * *-----------------------------------------------------------------------------* bset.b #FLAGB_AKey_down,gb_flags(gbl) ; indicate Menu activate key ; down cre005 bra cre_remove ; remove this event cre010 bset.l #IECODE_UP_PREFIX_R,d0 ; form keyrelease keycode cmp.w ie_Code(a3),d0 ; is it activate menu keyrelease ? beq cre014 ; yes, branch cre012 bclr.b #FLAGB_AKey_down,gb_flags(gbl) ; clear activate key down bra cre_keep ; keep this event cre014 btst.b #FLAGB_AKey_down,gb_flags(gbl) ; is activate key down still ; posted ? beq cre012 ; no, branch *-----------------------------------------------------------------------------* * The user pressed and released the menu activation key without * * hitting any other keys, find the current window and see if it has * * a menu. * *-----------------------------------------------------------------------------* move.l gb_IBase(gbl),a5 ; get intuitionbase move.l ib_ActiveWindow(a5),d0 ; get current window beq cre005 ; if none, branch move.l d0,a1 ; save pointer to current window move.l wd_MenuStrip(a1),d0 ; get window's menu beq cre005 ; if none, branch move.l d0,a0 ; save menu for use later move.l wd_Flags(a1),d0 ; get window's flags btst.l #MENUSTATE_B,d0 ; is a menu already active ? bne cre005 ; yes, branch *-----------------------------------------------------------------------------* * The current window has a menu, check the RMBTRAP flag. If this is * * set and the user didn't specify that we can clear it, then we * * can't use this menu. * *-----------------------------------------------------------------------------* btst.l #RMBTRAP_B,d0 ; is RMBTRAP set in window ? beq cre015 ; no, branch btst.b #FLAGB_Clear_rmbtrap,gb_flags(gbl) ; clear rmbtrap option ; set ? beq cre005 ; no, ignore the menu bclr.l #RMBTRAP_B,d0 ; clear RMBTRAP bit move.l d0,wd_Flags(a1) ; update window's flags *-----------------------------------------------------------------------------* * Finally, a menu we can use. Update our globals. * *-----------------------------------------------------------------------------* cre015 move.l a0,gb_menu(gbl) ; update our Menu pointer move.l a1,gb_window(gbl) ; update our window pointer *-----------------------------------------------------------------------------* * Now look to see if the menu and menu item saved in our globals is * * still valid for this menu. If so, we will position the mouse on * * them otherwise we'll put the mouse on the topmost item in the * * leftmost menu. * *-----------------------------------------------------------------------------* move.l gb_currentmenu(gbl),a1 ; get saved menu jsr Verify_Item ; go verify currentmenu bne cre020 ; does it exist ? yes, use it move.w #s_leftmost,d0 ; no, setup to find leftmost menu jsr Select_Item ; go select a Menu move.l d0,gb_currentmenu(gbl) ; update our globals with new menu cre020 move.l gb_currentmenu(gbl),a0 ; get current menu move.l mu_FirstItem(a0),a0 ; point to first menu item move.l gb_currentitem(gbl),a1 ; get current menu item jsr Verify_Item ; go verify current item bne cre025 ; does it exist ? yes, branch move.w #s_top,d0 ; no, setup to find top menuitem jsr Select_Item ; go select menu item move.l d0,gb_currentitem(gbl) ; update our globals *-----------------------------------------------------------------------------* * Save the current mouse position so we can put it back where we * * found it when we're done. set/clear various flags reflecting our * * current state. Three events are inserted in the event chain. * * A rawmouse menudown event that causes intuition to activate the * * menu followed by two pointerpos events to position the pointer * * first on the desired menu then on the menu item within that menu. * *-----------------------------------------------------------------------------* cre025 move.w ib_MouseX(a5),gb_old_MouseX(gbl) ; save current X move.w ib_MouseY(a5),gb_old_MouseY(gbl) ; save current Y clr.l gb_currentsubitem(gbl) ; no subitem at present move.w #MENUDOWN,d0 ; setup to insert a menudown event move.l a3,a1 ; event to attach new event to jsr Insert_RawMouse_Event ; go insert the rawmouse event moveq.l #2,d0 ; indicate 2 events to be built move.l a0,a1 ; event to attach new events to jsr db010 ; go build the necessary events bclr.b #FLAGB_AKey_down,gb_flags(gbl) ; no longer waiting for ; activate key down event move.l #req_setpointer,d0 ; setup to send request cre027 bchg.b #FLAGB_MActive,gb_flags(gbl) ; invert menu active bit jsr sendrequest ; send pointer req to our task bra cre_remove ; go to common return *-----------------------------------------------------------------------------* * A menu is currently active, check for the various keys that we * * care about. * *-----------------------------------------------------------------------------* cre035 move.b gb_DKey(gbl),d0 cmp.w ie_Code(a3),d0 ; Deactivate key ? bne cre040 ; no, branch *-----------------------------------------------------------------------------* * The menu 'deactivate' key was pressed. Three events are inserted * * in the event chain. They consist of a pointerpos event to * * position the pointer in the menu strip followed by a rawmouse * * menuup event that causes intuition to deactivate the menu without * * selecting anything followed by another pointerpos event to put * * the pointer back where we found it when the menu was activated. * *-----------------------------------------------------------------------------* moveq.l #3,d0 ; build 2 events jsr dobuild ; go build mouse event(s) move.w #MENUUP,d0 ; setup for a menu up rawmouse event move.l a0,a1 ; event to attach new event to jsr Insert_RawMouse_Event ; go insert the a rawmouse event move.l #req_clearpointer,d0 ; setup to restore pointer bra cre027 ; get out cre040 move.b gb_SKey(gbl),d0 cmp.w ie_Code(a3),d0 ; Select Key ? bne cre055 ; yes, branch *-----------------------------------------------------------------------------* * The menu 'select' key was pressed. Two events are inserted in the * * event chain. They consist of a menuup rawmouse event to select * * the current menu item, followed by a pointer event to put the * * pointer back where we found it when the menu was activated. * *-----------------------------------------------------------------------------* move.l a3,a1 ; event to attach new ones to move.w #MENUUP,d0 ; set type of rawmouse event jsr Insert_RawMouse_Event ; go insert a menuup event move.l gb_IBase(gbl),a5 ; get intuitionbase address move.w gb_old_MouseX(gbl),d0 ; get saved mouse x coordinate move.w gb_old_MouseY(gbl),d1 ; get saved mouse y cooridnate move.l a0,a1 ; event to attach new event to lea gb_ppos1(gbl),a0 ; new event to be inserted jsr Insert_PointerPos_Event move.l #req_clearpointer,d0 ; setup to restore pointer bra cre027 ; get out cre055 move.b gb_RightKey(gbl),d0 cmp.w ie_Code(a3),d0 ; Move Right ? bne cre060 ; no, branch move.w #s_adjacent_right,d1 ; 1st selection choice move.w #s_right,d2 ; 2nd selection choice move.w #s_leftmost,d3 ; 3rd selection choice bra cre065 cre060 move.b gb_LeftKey(gbl),d0 cmp.w ie_Code(a3),d0 ; Move Left ? bne cre125 ; no, branch move.w #s_adjacent_left,d1 ; 1st selection choice move.w #s_left,d2 ; 2nd selection choice move.w #s_rightmost,d3 ; 3rd selection choice cre065 move.b ie_Qualifier+1(a3),d0 ; get key qualifier and.b gb_Qual(gbl),d0 ; was qualifier key present ? beq cre067 ; no,branch *-----------------------------------------------------------------------------* * The menu 'right' or 'left' key was pressed. See if a qualifier * * key was also present. If so, we move to either rightmost or * * leftmost menu. * *-----------------------------------------------------------------------------* move.w #s_rightmost,d0 ; select rightmost cmp.w d0,d3 ; same selection ? bne cre107 ; no, branch move.w #s_leftmost,d0 ; select leftmost bra cre107 ; go choose the menu *-----------------------------------------------------------------------------* * The menu 'right' or 'left' key was pressed. Now we must see if * * a subitem list exists for the current menu item. * *-----------------------------------------------------------------------------* cre067 move.l gb_currentitem(gbl),a0 ; get current menu item ptr move.l mi_SubItem(a0),a1 ; get its menu subitem ptr, if any move.l a1,d0 ; set cc beq cre100 ; no subitems on this menu, branch *-----------------------------------------------------------------------------* * There are subitems attached to this menu item. Some explanation * * is in order here. With Intuition, menu subitems can be rendered * * anywhere on the menu display as long as at least one pixel of the * * menu subitem overlaps a pixel of its associated menu item. * * Generally, subitems are designed to appear either to the right of * * its associated menu item or to the left. This affects our * * interpretation of what the user wants to do when they press * * either the menu right or menu left key. For example, if the menu * * subitems are positioned to the right of the menu item and the * * menu right key is pressed, this means that the user intends to * * step into the menu subitem list. If the menu subitems are * * positioned on the left and the menu right key is pressed, the * * user wants to step to the next list of menu items on the right * * (or wrap to the first set of menu items if we are positioned on * * the rightmost menu item). Here we check the leftedge of the * * subitem against the leftedge of the menu item to determine if the * * subitem's leftedge is less than (or to the left of) the menu * * item's leftedge. The result of this comparison is saved in d4 and * * is used later in determining what the user's intentions are. * *-----------------------------------------------------------------------------* move.w mi_LeftEdge(a1),d0 ; get subitem's leftedge cmp.w mi_LeftEdge(a0),d0 ; compare to menuitem's leftedge slt d4 ; save comparison result tst.l gb_currentsubitem(gbl) ; are we processing subitems ? bne cre080 ; yes, branch *-----------------------------------------------------------------------------* * We are positioned on a menu item that has subitems attached and * * the user has pressed the menu right or menu left key. Determine * * what their intention is. Either they want to step into the * * subitem list or they want to select the next menu item. * *-----------------------------------------------------------------------------* clr.l d0 move.b gb_RightKey(gbl),d0 ; setup for compare cmp.w ie_Code(a3),d0 ; right key ? bne cre070 ; no, branch tst.b d4 ; are subitems on menu items left ? beq cre075 ; no, step into the subitem list bra cre100 ; yes, step to next menu item list cre070 tst.b d4 ; are subitems on menu items left ? beq cre100 ; no, step to next menu item list ; yes, step into the subitem list *-----------------------------------------------------------------------------* * The user wants to step into the subitem list. Select the topmost * * adjacent subitem in the list. (Note: there can be subitems * * positioned horizontally as well as vertically) * *-----------------------------------------------------------------------------* cre075 move.w #s_adjacent_top,d0 ; set to select the topmost subitem move.l a1,a0 ; list of subitems to choose from jsr Select_Item ; go find the subitem move.l d0,gb_currentsubitem(gbl) ; save it in our globals bra cre085 ; go generate an event *-----------------------------------------------------------------------------* * We are currently positioned on a menu subitem and the user has * * pressed either the menu right key or menu left key. Determine * * what their intention is. If there is another subitem positioned * * adjacent to the current subitem in the direction of the key that * * was pressed, that subitem will be selected. Otherwise, the user * * wants to step out of the subitem list. * *-----------------------------------------------------------------------------* cre080 move.l d1,d0 ; get 1st selection choice move.l a1,a0 ; list of subitems to choose from move.l gb_currentsubitem(gbl),a1 ; supply current subitem jsr Select_Item ; go select next subitem cmp.l d0,a1 ; same item selected ? beq cre090 ; yes, get out of the subitem list move.l d0,gb_currentsubitem(gbl) ; no, save new subitem cre085 moveq.l #1,d0 ; set to build only one event bra cre175 ; go generate an event *-----------------------------------------------------------------------------* * The user wants to step out of the subitem list. Determine whether * * they want to go back to the menu item associated with the subitem * * list or to the next menu item. * *-----------------------------------------------------------------------------* cre090 clr.l gb_currentsubitem(gbl) ; clear current subitem pointer clr.l d0 move.b gb_RightKey(gbl),d0 ; setup for compare cmp.w ie_Code(a3),d0 ; right key ? bne cre095 ; no, branch tst.b d4 ; are subitems on menu items left ? bne cre085 ; yes, go back to subitems menu item bra cre100 ; no, go select next menu item list cre095 tst.b d4 ; are subitems on menu items left ? beq cre085 ; no, go back to subitems menu item *-----------------------------------------------------------------------------* * Select a menu item. (Note: there can be menu items positioned * * horizontally as well as vertically) * *-----------------------------------------------------------------------------* cre100 move.l d1,d0 ; get 1st selection choice move.l gb_currentmenu(gbl),a0 ; get current menu move.l mu_FirstItem(a0),a0 ; list of items to choose from move.l gb_currentitem(gbl),a1 ; get current menu item jsr Select_Item ; go select an item cmp.l d0,a1 ; same item selected ? bne cre115 ; no, use the new item, branch *-----------------------------------------------------------------------------* * There are no menu items positioned in the horizontal direction of * * the key that was pressed, so we must step to the next menu. * *-----------------------------------------------------------------------------* move.l d2,d0 ; get 2nd selection choice move.l gb_menu(gbl),a0 ; list of menus to choose from move.l gb_currentmenu(gbl),a1 ; get current menu jsr Select_Item ; go select a menu cmp.l d0,a1 ; same menu selected ? beq cre105 ; yes, branch move.l d0,gb_currentmenu(gbl) ; no, use the new menu bra cre110 ; go select an item in the menu *-----------------------------------------------------------------------------* * There are no menus in the horizontal direction of the key that * * was pressed. We will interpret this to mean that the user wants * * to wrap to the opposite end of the menu strip. For example, if we * * are currently on the rightmost menu and the user presses the menu * * right key, we will wrap around to the leftmost menu. * *-----------------------------------------------------------------------------* cre105 move.l d3,d0 ; set 3rd selection choice cre107 move.l gb_menu(gbl),a0 ; list of menus to choose from jsr Select_Item ; go select again move.l d0,gb_currentmenu(gbl) ; save new menu cre110 move.w #s_top,d0 ; set to select topmost menu item move.l gb_currentmenu(gbl),a0 ; get current menu move.l mu_FirstItem(a0),a0 ; list of items to choose from jsr Select_Item ; go select a menu item move.l d0,gb_currentitem(gbl) ; save new item *-----------------------------------------------------------------------------* * Normally, we will generate only one event. A pointerpos event to * * position the pointer on the desired menu item or subitem. Here we * * have determined that a new menu is to be selected. This requires * * us to generate 2 events. The first will be a pointerpos event to * * position the pointer in the menu strip over the menu that we want * * to select. This causes Intuition to remove the rendering of the * * current menu from the display and render the menu that we are * * selecting. The second event will be a pointerpos event to * * position the pointer on the menu item that we have chosen. * *-----------------------------------------------------------------------------* moveq.l #2,d0 ; set number of events to build bra cre120 cre115 move.l d0,gb_currentitem(gbl) ; save new item moveq.l #1,d0 ; set number of events to build cre120 clr.l gb_currentsubitem(gbl) ; clear current subitem pointer bra cre175 ; go generate event(s) cre125 move.b gb_DownKey(gbl),d0 ; setup for compare cmp.w ie_Code(a3),d0 ; Down key ? bne cre130 ; no, branch move.w #s_adjacent_up,d1 ; 1st selection choice move.w #s_up,d2 ; 2nd selection choice move.w #s_top,d3 ; 3rd selection choice bra cre135 ; go handle keypress cre130 move.b gb_UpKey(gbl),d0 ; setup for compare cmp.w ie_Code(a3),d0 ; Up key ? bne cre_keep ; no, pass this event on move.w #s_adjacent_down,d1 ; 1st selection choice move.w #s_down,d2 ; 2nd selection choice move.w #s_bottom,d3 ; 3rd selection choice *-----------------------------------------------------------------------------* * The menu 'up' or 'down' key was pressed. If we are currently * * positioned in a subitem menu, setup to select the appropriate * * subitem otherwise setup to select the appropriate menu item. * *-----------------------------------------------------------------------------* cre135 moveq.l #1,d4 ; set default # events to be created tst.l gb_currentsubitem(gbl) ; are we processing subitems ? beq cre140 ; no, branch move.l gb_currentsubitem(gbl),a1 ; supply parameters to process move.l gb_currentitem(gbl),a0 ; menu subitems move.l mi_SubItem(a0),a0 bra cre145 cre140 move.l gb_currentitem(gbl),a1 ; supply parameters to process menu move.l gb_currentmenu(gbl),a0 ; items move.l mu_FirstItem(a0),a0 *-----------------------------------------------------------------------------* * Here we check to see if there are subitems attached to the * * current menu item. If so, we will generate 2 events. The first * * will be a pointerpos event to position the pointer on the menu * * strip. The second will be a pointerpos event to position the * * pointer on the desired menu item. This is done to cause Intuition * * to remove the subitem's rendering from the display in case it * * overlaps onto the menu item being selected. Without this, we * * would tell Intuition to position the mouse on the new menu item * * but the overlapping subitems from the current menu item would * * still be displayed causing us to select a menu subitem instead of * * the menu item that we intended to select. * *-----------------------------------------------------------------------------* tst.l mi_SubItem(a1) ; are there subitems attached to ; this menu item ? beq cre145 ; no, branch moveq.l #2,d4 ; yes, use 2 events to select item cre145 move.b ie_Qualifier+1(a3),d0 ; get key qualifier and.b gb_Qual(gbl),d0 ; was qualifier key present ? beq cre147 ; no, branch *-----------------------------------------------------------------------------* * See if a qualifier key was also present. If so, we move to either * * topmost or bottommost menu or submenu item. * *-----------------------------------------------------------------------------* move.w #s_bottom,d0 ; select bottom cmp.w d0,d3 ; same selection ? bne cre153 ; no, branch move.w #s_top,d0 ; select top bra cre153 cre147 move.l d1,d0 ; get 1st selection choice jsr Select_Item ; go select a menuitem or subitem cmp.l d0,a1 ; same item selected ? bne cre155 ; no, use the new one move.l d2,d0 ; get 2nd selection choice jsr Select_Item ; select again cre150 cmp.l d0,a1 ; same item selected ? bne cre155 ; no, use new item move.l d3,d0 ; get 3rd selection choice cre153 jsr Select_Item ; go select again cre155 move.l d0,a1 ; save new item cre160 tst.l gb_currentsubitem(gbl) ; are we processing subitems ? beq cre165 ; no, branch move.l a1,gb_currentsubitem(gbl) ; yes, save new subitem bra cre170 cre165 move.l a1,gb_currentitem(gbl) ; save new item cre170 move.l d4,d0 ; get # of events to be generated cre175 jsr dobuild ; go build our events *-----------------------------------------------------------------------------* * Indicate that the original input event passed to this routine is * * to be removed from the input event chain and return. * *-----------------------------------------------------------------------------* cre_remove moveq.l #1,d0 ; indicate old event to be removed bra cre_exit ; go to common return *-----------------------------------------------------------------------------* * Indicate that the original input event passed to this routine is * * to be kept in the input event chain and return. * *-----------------------------------------------------------------------------* cre_keep clr.l d0 ; indicate old event to be kept cre_exit movem.l (sp)+,creregs ; restore registers rts ; return to caller creregs reg a1-a3/a5/d2-d4 ******************************************************************************* * * * dobuild * * * * This routine is called by Check_RawKey_Event to perform a general * * call to the Build_PointerPos_Event routine. * * * * Input Registers: * * a3 - input event to attach new events to * * a4 - global work area * * * * Output Registers: * * a0 - new input event * * a1 - original input event * * * ******************************************************************************* dobuild move.l a3,a1 ; pass original input event db010 lea gb_ppos2(gbl),a0 ; point to our input event area jsr Build_PointerPos_Event ; go create our input events rts ; return to caller ******************************************************************************* * * * Verify_Item * * * * This routine is called by Check_RawKey_Event to verify if a menu or * * menu item is a member of a provided list of menu/menu items. * * * * Input Registers: * * a0 - menu/menu item list * * a1 - item to be verified. * * * * Output Registers: * * d0 - 0=no match, 1=match * * * ******************************************************************************* Verify_Item movem.l viregs,-(sp) vi010 cmp.l a0,a1 ; does this item match ? beq vi015 ; yes, branch move.l im_NextItem(a0),d0 ; get next item's address beq vi020 ; entire list scanned, branch move.l d0,a0 ; use next item's address bra vi010 ; loop to check next item vi015 moveq.l #1,d0 ; indicate that the item exists vi020 movem.l (sp)+,viregs rts viregs reg a0/a1 ******************************************************************************* * * * Select_Item * * * * This routine is called to select a menu, menu item or menu subitem. * * Given a list of items to choose from, the attribute of the item * * desired and the current item; this routine attempts to find a new * * item that matches the desired attribute. For example, if d0 contains * * 's_up' the list of items provided is scanned to find the closest item * * that is physically above the current item on the display. * * * * Input Registers: * * a0 - menu/menu item/menu subitem list * * a1 - current item * * d0 - type of item desired in relation to current item * * * * Output Registers: * * d0 - selected item (or current item if no item was selected) * * * ******************************************************************************* Select_Item select_type equr d0 ; select type & return value item equr a0 ; item list currentitem equr a1 ; currentitem returnitem equr a2 ; return item work equr d1 ; work register *-----------------------------------------------------------------------------* * 'returnitem' contains the address of the item that is being * * considered for return to the calling routine. Here we create a * * dummy item on the stack that contains extreme values for topedge * * and leftedge. The address of this entry is loaded into * * 'returnitem' to give us an initial entry to compare against. * * For example, if 's_leftmost' is the attribute of the item that we * * are searching for, the leftedge field in the dummy entry would * * contain 32768. In an effort to find the 'leftmost' item in the * * list, the 'si_leftmost' portion of this routine will compare the * * leftedge of each item in the list with the leftedge of * * 'returnitem'. When an item is found with a leftedge that is less * * than returnitem's, its address is placed in returnitem. When the * * end of the list is reached, the item with the lowest leftedge * * should be contained in 'returnitem' * *-----------------------------------------------------------------------------* link a5,#-im_size movem.l siregs,-(sp) move.w #32767,work cmp.w #s_leftmost,select_type ble si010 move.w #-32768,work si010 lea -im_size(a5),returnitem move.w work,im_TopEdge(returnitem) ; setup dummy item move.w work,im_LeftEdge(returnitem) bra si_jmp ; go to computed jump si_adjacent_up move.w im_LeftEdge(item),work cmp.w im_LeftEdge(currentitem),work bne si_check_end si_up move.w im_TopEdge(item),work cmp.w im_TopEdge(currentitem),work ble si_check_end si_top si_adjacent_top move.w im_TopEdge(item),work cmp.w im_TopEdge(returnitem),work bge si015 move.l item,returnitem si015 cmp.w #s_adjacent_top,select_type bne si_check_end move.w im_TopEdge(item),work cmp.w im_TopEdge(returnitem),work bne si_check_end move.w im_LeftEdge(item),work cmp.w im_LeftEdge(returnitem),work bge si_check_end move.l item,returnitem bra si_check_end si_adjacent_right move.w im_TopEdge(item),work cmp.w im_TopEdge(currentitem),work bne si_check_end si_right move.w im_LeftEdge(item),work cmp.w im_LeftEdge(currentitem),work ble si_check_end si_leftmost move.w im_LeftEdge(item),work cmp.w im_LeftEdge(returnitem),work bge si_check_end move.l item,returnitem bra si_check_end si_adjacent_down move.w im_LeftEdge(item),work cmp.w im_LeftEdge(currentitem),work bne si_check_end si_down move.w im_TopEdge(item),work cmp.w im_TopEdge(currentitem),work bge si_check_end si_bottom move.w im_TopEdge(item),work cmp.w im_TopEdge(returnitem),work ble si_check_end move.l item,returnitem bra si_check_end si_adjacent_left move.w im_TopEdge(item),work cmp.w im_TopEdge(currentitem),work bne si_check_end si_left move.w im_LeftEdge(item),work cmp.w im_LeftEdge(currentitem),work bge si_check_end si_rightmost move.w im_LeftEdge(item),work cmp.w im_LeftEdge(returnitem),work ble si_check_end move.l item,returnitem si_check_end move.l im_NextItem(item),item move.l item,work ; set cc beq si_end si_jmp jmp (pc,d0.w) ; jump to proper routine si_end lea -im_size(a5),item cmp.l item,returnitem ; still pointing to dummy item ? bne si_return ; no, branch move.l currentitem,returnitem ; yes, pass currentitem back si_return move.l returnitem,d0 ; set return movem.l (sp)+,siregs ; restore regs unlk a5 ; remove area from stack rts ; return to caller siregs reg d1/a0-a2 ******************************************************************************* * * * Insert_PointerPos_Event * * * * This routine creates a pointerpos event and attaches it to the input * * event provided. * * * * Input Registers: * * a0 - new event to be inserted * * a1 - input event to attach new event to * * d0 - Mouse X coordinate to place in new event * * d1 - Mouse Y coordinate to place in new event * * * * Output Registers: * * none. * * * ******************************************************************************* Insert_PointerPos_Event move.b #IECLASS_POINTERPOS,ie_Class(a0) ; build mousemove event move.w #IECODE_NOBUTTON,ie_Code(a0) move.w d0,ie_X(a0) ; set coordinates move.w d1,ie_Y(a0) bra ire010 ******************************************************************************* * * * Insert_RawMouse_Event * * * * This routine creates a rawmouse event and attaches it to the input * * event provided. * * * * Input Registers: * * a1 - input event to attach new event to * * d0 - type of rawmouse event * * * * Output Registers: * * none. * * * ******************************************************************************* Insert_RawMouse_Event lea gb_rawm(gbl),a0 move.b #IECLASS_RAWMOUSE,ie_Class(a0) ; build rawmouse event move.w d0,ie_Code(a0) clr.w ie_X(a0) clr.w ie_Y(a0) ire010 clr.b ie_SubClass(a0) clr.w ie_Qualifier(a0) move.l ie_NextEvent(a1),ie_NextEvent(a0) ; chain to original event move.l a0,ie_NextEvent(a1) rts ; return to caller ******************************************************************************* * * * Build_PointerPos_Event * * * * This routine creates pointer position event(s) and attaches them to * * the input event provided. The resolution of the current screen is * * taken into account when generating the events. The coordinates of the * * pointer position events are alway represented in the highest * * resolution i.e. 640x400. The coordinate fields of menus, menu items, * * etc. are represented in the resolution of the screen to which the * * menu is attached. When we position the pointer on anything but a * * hires interlace screen, we must adjust the coordinates that are taken * * from the menus to allow for this. * * * * Input Registers: * * a0 - address of input event to be built * * a1 - original input event * * d0 - number of input events to generate. * * * * Output Registers: * * none. * * * ******************************************************************************* Build_PointerPos_Event iheight equr d1 iwidth equr d1 itopedge equr d2 ileftedge equr d2 mheight equr d3 mwidth equr d3 mtopedge equr d4 mleftedge equr d4 offsetx equr d5 offsety equr d6 movem.l breregs,-(sp) ; save registers jsr Insert_PointerPos_Event ; go insert new event move.l gb_window(gbl),a2 ; get current window move.l wd_WScreen(a2),a2 ; get window's screen move.l gb_currentmenu(gbl),a3 ; get current menu move.w mu_TopEdge(a3),mtopedge ; get menu's topedge add.w sc_ViewPort+vp_DyOffset(a2),mtopedge ; add screen's offset swap mtopedge move.w mu_LeftEdge(a3),mleftedge ; get menu's leftedge add.w sc_ViewPort+vp_DxOffset(a2),mleftedge ; add screen's offset clr.l mheight move.b sc_BarHeight(a2),mheight ; get menu's height swap mheight move.w mu_Width(a3),mwidth ; get menu's width move.l gb_currentitem(gbl),a3 ; get current menuitem move.w mi_TopEdge(a3),itopedge ; get menuitem's topedge swap itopedge move.w mi_LeftEdge(a3),ileftedge ; get menuitem's leftedge move.w mi_Height(a3),iheight ; get menuitem's height swap iheight move.w mi_Width(a3),iwidth ; get menuitem's width move.l gb_currentsubitem(gbl),a5 ; is there a subitem ? move.l a5,d5 ; set cc beq bre010 ; no, branch add.w mi_LeftEdge(a5),ileftedge ; yes, add subitem's leftedge move.w mi_Width(a5),iwidth ; use subitem's width swap ileftedge add.w mi_TopEdge(a5),itopedge ; add subitem's topedge swap itopedge swap iwidth move.w mi_Height(a5),iheight ; use subitem's height swap iheight bra bre025 bre010 move.l mi_SubItem(a3),a5 ; is there a subitem for this item ? move.l a5,d5 ; set cc beq bre025 ; no, branch move.w mi_LeftEdge(a5),d5 ; yes, get subitem's leftedge cmp.w mi_LeftEdge(a3),d5 ; is it's leftedge less than item's? bge bre020 ; no, branch add.w d5,ileftedge ; yes, add subitems leftedge add.w mi_Width(a5),ileftedge ; add subitem's width move.w mi_LeftEdge(a3),iwidth ; get items leftedge add.w mi_Width(a3),iwidth ; add its width move.l ileftedge,d5 ; get item's leftedge bge bre015 ; if its positive, branch neg d5 ; make it positive bre015 sub.w d5,iwidth bra bre025 bre020 movem.l d0/a0,-(sp) ; save our registers move.l a5,a0 ; pass subitem pointer move.l #s_adjacent_top,d0 ; set select type jsr Select_Item move.l d0,a5 ; get selected item movem.l (sp)+,d0/a0 ; restore our registers move.w mi_LeftEdge(a5),iwidth sub.w #1,iwidth bre025 move.w sc_ViewPort+vp_Modes(a2),d5 ; get screen modes btst.l #V_HIRES_B,d5 ; is this a hires screen ? bne bre030 ; yes, branch asl.w #1,iwidth ; no, adjust coordinates for hires asl.w #1,ileftedge asl.w #1,mwidth asl.w #1,mleftedge bre030 btst.l #V_LACE_B,d5 ; is this an interlace screen ? bne bre035 ; yes, branch swap iwidth ; no, adjust coordinates for interlace swap ileftedge swap mwidth swap mleftedge asl.w #1,iheight asl.w #1,itopedge asl.w #1,mheight asl.w #1,mtopedge swap iheight swap itopedge swap mheight swap mtopedge bre035 move.l gb_IBase(gbl),a5 ; get intuition base addq.w #1,mleftedge move.w mleftedge,offsetx ; get menu leftedge move.w offsetx,ie_X(a0) ; update event's X coordinate swap mleftedge addq.w #1,mtopedge move.w mtopedge,offsety ; get menu topedge move.w offsety,ie_Y(a0) ; update event's Y coordinate asr.w #1,mwidth ; divide menu width by 2 move.w ileftedge,offsetx ; get item leftedge asr.w #1,iwidth ; divide item width by 2 add.w iwidth,offsetx ; add it to offsetx swap mwidth move.w mheight,offsety ; get menu height asr.w #1,mheight ; divide menu height by 2 swap mheight swap ileftedge add.w itopedge,offsety ; add item topedge swap iwidth asr #1,iheight ; divide item height by 2 add.w iheight,offsety ; add to offsety cmp.w #1,d0 ; one event to be generated ? bne bre040 ; no, branch add.w offsetx,ie_X(a0) ; adjust mouse x coordinate add.w offsety,ie_Y(a0) ; adjust mouse y coordinate bra bre045 bre040 cmp.w #3,d0 ; go to saved mouse position ? bne bre042 ; no, branch move.w gb_old_MouseX(gbl),offsetx move.w gb_old_MouseY(gbl),offsety bra bre044 bre042 add.w ie_X(a0),offsetx add.w ie_Y(a0),offsety bre044 add.w mwidth,ie_X(a0) ; add menu width to current item swap mwidth add.w mheight,ie_Y(a0) ; add menu height to current item move.l a0,a1 ; event to attach new event to lea gb_ppos1(gbl),a0 ; new event area move.w offsetx,d0 move.w offsety,d1 jsr Insert_PointerPos_Event ; go add the event to the chain bre045 bset.b #FLAGB_Events_inserted,gb_flags(gbl) ; indicate events added movem.l (sp)+,breregs rts ; return to caller breregs reg a0-a5/d1-d6 end