;/* 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);
}