;/* strhooks.c - Execute me to compile me with SAS C 5.10 LC -b1 -cfistq -v -y -j73 strhooks.c Blink FROM LIB:c.o,strhooks.o TO strhooks LIBRARY LIB:LC.lib,LIB:Amiga.lib quit ** strhooks.c - string gadget hooks demo ** ** WARNING: This file contains "callback" functions. ** You must disable stack checking (SAS -v flag) for them to work. */ #define INTUI_V36_NAMES_ONLY #include <exec/types.h> #include <exec/memory.h> #include <utility/hooks.h> #include <devices/inputevent.h> #include <intuition/intuition.h> #include <intuition/sghooks.h> #include <graphics/displayinfo.h> #include <clib/intuition_protos.h> #include <clib/utility_protos.h> #include <clib/exec_protos.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ int chkabort(void) { return(0); } /* really */ #endif /* our function prototypes */ BOOL IsHexDigit(UBYTE test_char); ULONG str_hookRoutine(struct Hook *hook, struct SGWork *sgw, ULONG *msg); void initHook(struct Hook *hook, ULONG (*ccode)()); VOID handleWindow(struct Vars *vars); struct Library *IntuitionBase; struct Library *UtilityBase; #define SG_STRLEN (44) #define MYSTRGADWIDTH (200) #define INIT_LATER 0 /* A border for the string gadget */ UWORD strBorderData[] = /* init elements 5 and 7 later (height adjust) */ { 0,0, MYSTRGADWIDTH + 3,0, MYSTRGADWIDTH + 3,INIT_LATER, 0,INIT_LATER, 0,0, }; struct Border strBorder = { -2,-2, 1, 0,JAM1,5,strBorderData,NULL, }; /* We'll dynamically allocate/clear most structures, buffers */ struct Vars { struct Window *sgg_Window; struct Gadget sgg_Gadget; struct StringInfo sgg_StrInfo; struct StringExtend sgg_Extend; struct Hook sgg_Hook; UBYTE sgg_Buff[SG_STRLEN]; UBYTE sgg_WBuff[SG_STRLEN]; UBYTE sgg_UBuff[SG_STRLEN]; }; /* Main entry point. ** ** Open all required libraries, set-up the string gadget. ** Prepare the hook, open the sgg_Window and go... */ VOID main(int argc, char **argv) { struct Vars *vars; struct Screen *screen; struct DrawInfo *drawinfo; if (IntuitionBase = OpenLibrary("intuition.library", 37L)) { if (UtilityBase = OpenLibrary("utility.library", 37L)) { /* get the correct pens for the screen. */ if (screen = LockPubScreen(NULL)) { if (drawinfo = GetScreenDrawInfo(screen)) { vars = (struct Vars *)AllocMem(sizeof(struct Vars),MEMF_CLEAR); if (vars != NULL) { vars->sgg_Extend.Pens[0] = drawinfo->dri_Pens[FILLTEXTPEN]; vars->sgg_Extend.Pens[1] = drawinfo->dri_Pens[FILLPEN]; vars->sgg_Extend.ActivePens[0] = drawinfo->dri_Pens[FILLTEXTPEN]; vars->sgg_Extend.ActivePens[1] = drawinfo->dri_Pens[FILLPEN]; vars->sgg_Extend.EditHook = &(vars->sgg_Hook); vars->sgg_Extend.WorkBuffer = vars->sgg_WBuff; vars->sgg_StrInfo.Buffer = vars->sgg_Buff; vars->sgg_StrInfo.UndoBuffer = vars->sgg_UBuff; vars->sgg_StrInfo.MaxChars = SG_STRLEN; vars->sgg_StrInfo.Extension = &(vars->sgg_Extend); /* There should probably be a border around the string gadget. ** As is, it is hard to locate when disabled. */ vars->sgg_Gadget.LeftEdge = 20; vars->sgg_Gadget.TopEdge = 30; vars->sgg_Gadget.Width = MYSTRGADWIDTH; vars->sgg_Gadget.Height = screen->RastPort.TxHeight; vars->sgg_Gadget.Flags = GFLG_GADGHCOMP | GFLG_STRINGEXTEND; vars->sgg_Gadget.Activation = GACT_RELVERIFY; vars->sgg_Gadget.GadgetType = GTYP_STRGADGET; vars->sgg_Gadget.SpecialInfo = &(vars->sgg_StrInfo); vars->sgg_Gadget.GadgetRender = (APTR)&strBorder; strBorderData[5] = strBorderData[7] = screen->RastPort.TxHeight + 3; initHook(&(vars->sgg_Hook), str_hookRoutine); if (vars->sgg_Window = OpenWindowTags(NULL, WA_PubScreen, screen, WA_Left, 21, WA_Top, 20, WA_Width, 500, WA_Height, 150, WA_MinWidth, 50, WA_MaxWidth, ~0, WA_MinHeight, 30, WA_MaxHeight, ~0, WA_SimpleRefresh, TRUE, WA_NoCareRefresh, TRUE, WA_RMBTrap, TRUE, WA_IDCMP, IDCMP_GADGETUP | IDCMP_CLOSEWINDOW, WA_Flags, WFLG_CLOSEGADGET | WFLG_NOCAREREFRESH | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIMPLE_REFRESH, WA_Title, "String Hook Accepts HEX Digits Only", WA_Gadgets, &(vars->sgg_Gadget), TAG_DONE)) { handleWindow(vars); CloseWindow(vars->sgg_Window); } FreeMem(vars,sizeof(struct Vars)); } FreeScreenDrawInfo(screen, drawinfo); } UnlockPubScreen(NULL, screen); } CloseLibrary(UtilityBase); } CloseLibrary(IntuitionBase); } } /* ** This is an example string editing hook, which shows the basics of ** creating a string editing function. This hook restricts entry to ** hexadecimal digits (0-9, A-F, a-f) and converts them to upper case. ** To demonstrate processing of mouse-clicks, this hook also detects ** clicking on a character, and converts it to a zero. ** ** NOTE: String editing hooks are called on Intuition's task context, ** so the hook may not use DOS and may not cause Wait() to be called. */ ULONG str_hookRoutine(struct Hook *hook, struct SGWork *sgw, ULONG *msg) { UBYTE *work_ptr; ULONG return_code; /* Hook must return non-zero if command is supported. ** This will be changed to zero if the command is unsupported. */ return_code = ~0L; if (*msg == SGH_KEY) { /* key hit -- could be any key (Shift, repeat, character, etc.) */ /* allow only upper case characters to be entered. ** act only on modes that add or update characters in the buffer. */ if ((sgw->EditOp == EO_REPLACECHAR) || (sgw->EditOp == EO_INSERTCHAR)) { /* Code contains the ASCII representation of the character ** entered, if it maps to a single byte. We could also look ** into the work buffer to find the new character. ** ** sgw->Code == sgw->WorkBuffer[sgw->BufferPos - 1] ** ** If the character is not a legal hex digit, don't use ** the work buffer and beep the screen. */ if (!IsHexDigit(sgw->Code)) { sgw->Actions |= SGA_BEEP; sgw->Actions &= ~SGA_USE; } else { /* And make it upper-case, for nicety */ sgw->WorkBuffer[sgw->BufferPos - 1] = ToUpper(sgw->Code); } } } else if (*msg == SGH_CLICK) { /* mouse click ** zero the digit clicked on */ if (sgw->BufferPos < sgw->NumChars) { work_ptr = sgw->WorkBuffer + sgw->BufferPos; *work_ptr = '0'; } } else { /* UNKNOWN COMMAND ** hook should return zero if the command is not supported. */ return_code = 0; } return(return_code); } /* ** This is a function which converts register-parameter ** hook calling convention into standard C conventions. ** It only works with SAS C 5.0+ ** ** Without the fancy __asm stuff, you'd probably need to ** write this in assembler. ** ** You could conceivably declare all your C hook functions ** this way, and eliminate the middleman (you'd initialize ** the h_Entry field to your C function's address, and not ** bother with the h_SubEntry field). ** ** This is nice and easy, though, and since we're using the ** small data model, using a single interface routine like this ** (which does the necessary __saveds), it might ** actually turn out to be smaller to use a single entry point ** like this rather than declaring each of many hooks __saveds. */ ULONG __saveds __asm hookEntry(register __a0 struct Hook *hookptr, register __a2 void *object, register __a1 void *message) { return((*hookptr->h_SubEntry)(hookptr, object, message)); } /* ** Initialize the hook to use the hookEntry() routine above. */ void initHook(struct Hook *hook, ULONG (*ccode)()) { hook->h_Entry = hookEntry; hook->h_SubEntry = ccode; hook->h_Data = 0; /* this program does not use this */ } /* ** Process messages received by the sgg_Window. Quit when the close gadget ** is selected. */ VOID handleWindow(struct Vars *vars) { struct IntuiMessage *msg; ULONG class; USHORT code; for (;;) { Wait(1L << vars->sgg_Window->UserPort->mp_SigBit); while (msg = (struct IntuiMessage *)GetMsg(vars->sgg_Window->UserPort)) { /* Stash message contents and reply, important when message ** triggers some lengthy processing */ class = msg->Class; code = msg->Code; ReplyMsg((struct Message *)msg); switch (class) { case IDCMP_GADGETUP: /* if a code is set in the hook after an SGH_KEY ** command, where SGA_END is set on return from ** the hook, the code will be returned in the Code ** field of the IDCMP_GADGETUP message. */ break; case IDCMP_CLOSEWINDOW: return; break; } } } } /* ** IsHexDigit() ** ** Return TRUE if the character is a hex digit (0-9, A-F, a-f) */ BOOL IsHexDigit(UBYTE test_char) { test_char = ToUpper(test_char); if (((test_char >= '0') && (test_char <= '9')) || ((test_char >= 'A') && (test_char <= 'F'))) return(TRUE); else return(FALSE); }