home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
244.lha
/
KeyClick
/
keyclick.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-05-03
|
17KB
|
515 lines
/* Keyclick V1.1 by Mike M. Duppong [3/29/88] */
/* Last modified: 11/25/88 */
/* Written in Aztec C V3.6A */
/* Compile: cc keyclick.c */
/* Link: ln keyclick.o -lc */
/* Note: all of my routine and variable names are in lower case letters
* only. The Amiga system calls almost always contain at least one
* capital letter. In using this convention, I hope to simplify the
* distinction between my calls and the system calls. */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/errors.h>
#include <exec/devices.h>
#include <exec/execbase.h>
#include <intuition/intuition.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <devices/audio.h>
#include <functions.h>
#define SCREENTITLE "Keyclick V1.1 by Mike Duppong"
#define WINDOWTITLE "Keyclick"
#define HANDLER_PRIORITY 51 /* Priority of input handler */
#define AUDIO_PRIORITY -90 /* Priority of click sound */
#define TASK_PRIORITY 40L /* Priority of this task */
#define WAVELENGTH 16L /* # of bytes in waveform */
#define PERIOD 1L /* Waveform period */
#define CYCLES 25L /* Number of waveform cycles */
#define WINDOWX 0 /* Window's LeftEdge */
#define WINDOWY 13 /* Window's TopEdge */
#define WINDOWW 174 /* Window width */
#define WINDOWH 24 /* Window height */
#define VOLGADX 13 /* Volume gadget's LeftEdge */
#define VOLGADY 12 /* Volume gadget's TopEdge */
#define VOLGADW 128 /* Volume gadget's width */
#define VOLGADH 8 /* Volume gadget's height */
#define VOLGADID 1 /* Volume gadget ID */
#define SWTGADX (VOLGADX + VOLGADW + 10) /* LeftEdge */
#define SWTGADY 11 /* Switch gadget's TopEdge */
#define SWTGADW 9 /* Switch gadget's pixel width */
#define SWTGADWW ((SWTGADW + 15) / 16) /* word width */
#define SWTGADD 1 /* # of planes in gadget image */
#define SWTGADH 12 /* Switch gadget's height */
#define SWTGADID 2 /* Switch gadget ID */
#define CLUP_INPDEV 1 /* Close-up flags for cleanup() */
#define CLUP_AUDDEV 2 /* Audio device */
#define CLUP_HANDLER 4 /* Remove handler */
struct IOStdReq *iostdreq;
struct IOAudio *ioaudio;
struct Interrupt interrupt;
struct MsgPort *input_port, *audio_port;
struct IntuitionBase *IntuitionBase;
struct Window *window;
struct PropInfo prop;
struct Image vol_image;
struct Image onswt_image =
{
0, 0, /* LeftEdge, TopEdge */
SWTGADW, SWTGADH, SWTGADD,/* Width, Height, Depth */
NULL, /* ImageData - set below */
0x1, 0, /* PlanePick, PlaneOnOff */
NULL /* NextImage */
};
struct Image offswt_image =
{
0, 0, /* LeftEdge, TopEdge */
SWTGADW, SWTGADH, SWTGADD,/* Width, Height, Depth */
NULL, /* ImageData - set below */
0x1, 0, /* PlanePick, PlaneOnOff */
NULL /* NextImage */
};
struct Gadget switch_gadget =
{
NULL, /* NextGadget - none */
SWTGADX, SWTGADY, /* LeftEdge, TopEdge */
SWTGADW, SWTGADH, /* Width, Height */
SELECTED | GADGHIMAGE | GADGIMAGE, /* Flags */
GADGIMMEDIATE | RELVERIFY | TOGGLESELECT, /* Activation */
BOOLGADGET, /* GadgetType */
NULL, /* GadgetRender - set below */
NULL, /* SelectRender - set below */
NULL, /* GadgetText */
NULL, /* MutualExclude */
NULL, /* SpecialInfo */
SWTGADID, /* GadgetID */
NULL /* UserData */
};
struct Gadget volgadget =
{
&switch_gadget, /* NextGadget */
VOLGADX, VOLGADY, /* LeftEdge, TopEdge */
VOLGADW, VOLGADH, /* Width, Height */
GADGHCOMP, /* Flags */
GADGIMMEDIATE | RELVERIFY,/* Activation */
PROPGADGET, /* GadgetType */
NULL, /* GadgetRender- set below */
NULL, /* SelectRender */
NULL, /* GadgetText */
NULL, /* MutualExclude */
(APTR)&prop, /* SpecialInfo */
VOLGADID, /* GadgetID */
NULL /* UserData */
};
struct NewWindow windowdef =
{
WINDOWX, WINDOWY, WINDOWW, WINDOWH, /* X, Y, W, H */
0, 1, /* Detail/block pen */
CLOSEWINDOW | GADGETUP, /* IDCMP flags */
NOCAREREFRESH | SMART_REFRESH | ACTIVATE | WINDOWDRAG |
WINDOWDEPTH | WINDOWCLOSE, /* Flags */
&volgadget, /* First gadget */
NULL, /* Check mark */
(UBYTE *)WINDOWTITLE, /* Title */
NULL, /* Screen */
NULL, /* Bitmap */
0, 0, 0, 0, /* Min & Max Width & Height */
WBENCHSCREEN /* Workbench window */
};
UBYTE allocation[] = {1, 8, 2, 4}; /* Channel allocation */
BYTE *waveform; /* Pointer to waveform RAM */
UWORD onswt_data[] =
{
0x0000, 0x0800, 0x1C00, 0x1C00, 0x3E00, 0xDD80,
0x8880, 0xC180, 0x3E00, 0x0000, 0x0000, 0x0000
};
UWORD offswt_data[] =
{
0x0000, 0x0000, 0x0000, 0x0000, 0x3C00, 0xC180,
0x8880, 0xDD80, 0x3E00, 0x1C00, 0x1C00, 0x0800
};
struct infostruct /* Information passed between program and input handler */
{
struct Task *taskp;
ULONG key_signal;
struct Gadget *gadget;
} ih_info;
int clup;
int volume = 63; /* Click volume */
void handler_interface();
main()
{
init_gadgets();
open_window();
init_sound();
init_info();
open_input_device();
add_handler();
watch();
/* cleanup() is used by watch() to exit this program. */
}
init_gadgets()
{
init_slider();
init_switch();
}
init_slider()
{
/* Initialize pointers to image RAM */
volgadget.GadgetRender = (APTR)&vol_image;
/* Set slider to horizontally-moving auto-knob */
prop.Flags = AUTOKNOB | FREEHORIZ;
prop.HorizPot = 0xFFFF; /* Pegged to begin with */
prop.HorizBody = 0xFFFF / 32;
}
init_switch()
{
register int i;
/* Allocate RAM for on-switch image data */
if((onswt_image.ImageData = AllocMem((long)
(SWTGADWW * SWTGADH * SWTGADD * 2), MEMF_CHIP)) == NULL)
cleanup("Not enough memory.");
/* Allocate RAM for off-switch image */
if((offswt_image.ImageData = AllocMem((long)
(SWTGADWW * SWTGADH * SWTGADD * 2), MEMF_CHIP)) == NULL)
cleanup("Not enough memory.");
/* Move switch image data to CHIP memory */
for(i=0; i<SWTGADWW * SWTGADH * SWTGADD; i++)
{
*((UWORD *)(onswt_image.ImageData + i)) = onswt_data[i];
*((UWORD *)(offswt_image.ImageData + i)) = offswt_data[i];
}
/* Point to appropriate image structures */
switch_gadget.GadgetRender = (APTR)&offswt_image;
switch_gadget.SelectRender = (APTR)&onswt_image;
}
open_window()
{
short exists;
if((IntuitionBase = OpenLibrary("intuition.library", 1L)) == NULL)
error("Can't open Intuition library.");
/* Look for an already existing message port named "keyclick.audio."
* If it exists, another key-clicker is active in the system and this
* program will abort. */
if((ULONG)FindPort("keyclick.audio") != NULL)
{
/* Move window over a tad to avoid obscuring the original (should it
* remain unmoved) */
windowdef.LeftEdge += 5;
windowdef.TopEdge += 5;
exists = TRUE;
}
else exists = FALSE;
if((window = OpenWindow(&windowdef)) == NULL)
error("Can't open a window.");
if(exists == TRUE)
error("A key-clicker is already active!");
}
init_sound()
{
register int i;
if((ioaudio = AllocMem((long)sizeof(struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
error("Can't allocate RAM for IOAudio structure.\n");
if((audio_port = CreatePort("keyclick.audio", NULL)) == NULL)
cleanup("Can't create audio message port.");
if((OpenDevice("audio.device", NULL, ioaudio, NULL)) != NULL)
error("Audio device failed to open.");
clup |= CLUP_AUDDEV;
if((waveform = AllocMem(WAVELENGTH, MEMF_CHIP)) == NULL)
error("Can't allocate memory for waveform.");
for(i=0; i<WAVELENGTH; i++) /* Create a triangle waveform */
{
waveform[i / 2] = i * 127 / WAVELENGTH;
waveform[i / 2 + (WAVELENGTH / 2)] = (127 - i) * WAVELENGTH / 127;
}
}
init_info() /* Initializes the info structure */
{
ih_info.taskp = FindTask(NULL); /* Pointer to this task */
SetTaskPri(ih_info.taskp, TASK_PRIORITY); /* Set appropriate priority */
ih_info.key_signal = AllocSignal(-1L); /* Get a signal to talk to in.han. */
if(ih_info.key_signal == -1) /* Check for correct allocation */
error("Can't allocate a signal");
ih_info.gadget = &switch_gadget; /* Input handler must know about this */
}
open_input_device()
{
if((input_port = CreatePort("keyclick.input", NULL)) == NULL)
error("Can't create an input device message port.");
if((iostdreq = CreateStdIO(input_port)) == NULL)
error("Can't create an IOStdReq structure.");
if((OpenDevice("input.device", NULL, iostdreq, NULL)) != NULL)
error("Cannot open input device.");
clup |= CLUP_INPDEV;
}
add_handler()
{
interrupt.is_Code = handler_interface; /* Pointer to assembly interface */
interrupt.is_Data = (APTR)&ih_info; /* Pointer to mem needed by hand. */
interrupt.is_Node.ln_Pri = HANDLER_PRIORITY; /* Input handler priority */
iostdreq->io_Command = IND_ADDHANDLER;
iostdreq->io_Data = (APTR)&interrupt;
DoIO(iostdreq);
clup |= CLUP_HANDLER;
}
watch() /* Watches input device port for messages */
{
struct IntuiMessage *msg, *dqmsg;
struct Gadget *gadget;
ULONG mclass, sig;
/* Remove all waiting messages (if any) from window's IDCMP first */
while((dqmsg = (struct IntuiMessage *)GetMsg(window->UserPort)))
ReplyMsg(dqmsg);
SetWindowTitles(window, -1L, SCREENTITLE);
while(1)
{
/* Wait for a signal from Intuition or the custom input handler */
sig = Wait((ULONG)(1L << ih_info.key_signal) |
(ULONG)(1L << (ULONG)window->UserPort->mp_SigBit));
/* If the signal was from the input handler... */
if(sig & (ULONG)(1L << ih_info.key_signal))
click();
/* If the signal was from Intuition... */
if(sig & (ULONG)(1L << (ULONG)window->UserPort->mp_SigBit))
{
/* Take the message from the IDCMP */
msg = (struct IntuiMessage *) GetMsg(window->UserPort);
/* Make a copy of the message class */
mclass = msg->Class;
/* Also make a copy of which gadget was pressed (if any) */
gadget = (struct Gadget *)msg->IAddress;
/* Reply to the message before processing it */
ReplyMsg(msg); /* Reply to sender */
switch(mclass)
{
case CLOSEWINDOW: cleanup(); break; /* If close-gadget hit... */
case GADGETUP: /* If a gadget has been pressed (let up on) */
if(gadget->GadgetID == SWTGADID) /* Switch? */
toggle_click(); /* Yes, toggle the click */
else if(gadget->GadgetID == VOLGADID) /* Volume slider? */
adjust_volume(); /* Yes, adjust to new volume level */
break;
}
}
}
}
toggle_click() /* Enables/disables volume gadget */
{
if(switch_gadget.Flags & (WORD)SELECTED)
OnGadget(&volgadget, window, NULL);
else
OffGadget(&volgadget, window, NULL);
}
get_audio_channel() /* Allocates a free audio channel (if any) */
{
ioaudio->ioa_Request.io_Command = ADCMD_ALLOCATE;
ioaudio->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
ioaudio->ioa_AllocKey = 0; /* Generate new key */
ioaudio->ioa_Request.io_Message.mn_Node.ln_Pri = AUDIO_PRIORITY;
ioaudio->ioa_Request.io_Message.mn_ReplyPort = audio_port;
ioaudio->ioa_Data = allocation;
ioaudio->ioa_Length = (long)sizeof(allocation);
BeginIO(ioaudio);
}
free_audio_channel() /* Frees up a previously allocated audio channel */
{
ioaudio->ioa_Request.io_Command = ADCMD_FREE;
ioaudio->ioa_Request.io_Flags = IOF_QUICK | ADIOF_SYNCCYCLE;
BeginIO(ioaudio);
}
adjust_volume() /* Record new volume in the variable "volume" */
{
volume = ((long)(prop.HorizPot) * 64L) >> 16;
}
click() /* Take care of all things required to produce a click */
{
get_audio_channel(); /* Allocate a channel */
if((long)ioaudio->ioa_Request.io_Unit == NULL) /* If channel not avail...*/
return;
/* Fill in the ioaudio structure with appropriate parameters */
ioaudio->ioa_Request.io_Command = CMD_WRITE;
ioaudio->ioa_Request.io_Flags = ADIOF_PERVOL | IOF_QUICK | ADIOF_NOWAIT;
ioaudio->ioa_Data = (UBYTE *)waveform;
ioaudio->ioa_Length = WAVELENGTH;
ioaudio->ioa_Period = PERIOD;
ioaudio->ioa_Volume = (ULONG)volume;
ioaudio->ioa_Cycles = CYCLES;
BeginIO(ioaudio); /* Send off audio command */
WaitIO(ioaudio); /* Wait for CMD_WRITE operation to complete */
free_audio_channel(); /* Free up the audio channel */
}
remove_handler() /* Removes the custom input handler from system list */
{
iostdreq->io_Command = IND_REMHANDLER;
iostdreq->io_Data = (APTR)&interrupt;
DoIO(iostdreq);
}
struct InputEvent *input_handler(event, info_str) /* The informer */
register struct InputEvent *event;
register struct infostruct *info_str;
{
/* If toggle switch is in the on-position
If a RAWKEY (down-key) event is intercepted OR
a raw mouse event (button pressed)
Signal the waiting task to make a click. */
if(info_str->gadget->Flags & (WORD)SELECTED)
if((event->ie_Class == IECLASS_RAWKEY &&
!(event->ie_Code & IECODE_UP_PREFIX)) ||
(event->ie_Class == IECLASS_RAWMOUSE &&
(event->ie_Code == IECODE_LBUTTON ||
event->ie_Code == IECODE_RBUTTON ||
event->ie_Code == IECODE_MBUTTON)))
Signal(info_str->taskp, (ULONG)(1L << info_str->key_signal));
return(event);
}
error(message)
char *message;
{
struct IntuiMessage *msg;
ULONG mclass = NULL;
/* If the window opened okay, place the error message in
the Workbench screen's title bar and wait for the window
to close. Otherwise, attempt to output the message to
a CLI window with puts(). */
if(window != NULL) /* If opened successfully... */
{
/* Turn off gadgets */
OffGadget(&volgadget, window, NULL);
OffGadget(&switch_gadget, window, NULL);
SetWindowTitles(window, -1L, message); /* Set title to error message */
while(mclass != CLOSEWINDOW) /* Wait for a CLOSEWINDOW message */
{
WaitPort(window->UserPort); /* Wait for a message */
msg = (struct IntuiMessage *) GetMsg(window->UserPort);
mclass = msg->Class; /* Grab message class */
ReplyMsg(msg); /* Reply to message */
}
}
else puts(message); /* Try to output to CLI if window isn't open */
cleanup(); /* Do the standard cleanup from here. */
}
cleanup()
{
struct Message *dqmsg;
if(clup & CLUP_HANDLER) /* Remove the handler from system */
remove_handler();
if(ih_info.key_signal != -1) /* Deallocate handler-to-task signal */
FreeSignal((ULONG)(1L << ih_info.key_signal));
if(clup & CLUP_INPDEV) /* Close input device */
CloseDevice(iostdreq);
if(iostdreq) /* Delete created structure */
DeleteStdIO(iostdreq);
if(clup & CLUP_AUDDEV) /* Close audio device */
CloseDevice(ioaudio);
if(waveform != NULL) /* Free waveform memory */
FreeMem(waveform, WAVELENGTH);
if(ioaudio != NULL) /* Free IOAudio structure */
FreeMem(ioaudio, (long)sizeof(struct IOAudio));
if(input_port) /* Remove input device message port */
DeletePort(input_port);
if(audio_port) /* Remove audio device message port */
DeletePort(audio_port);
if(window != NULL) /* Dequeue message port and close window */
{ /* Make sure all messages are answered to free all memory */
while((dqmsg = GetMsg(window->UserPort))) ReplyMsg(dqmsg);
CloseWindow(window);
}
if(onswt_image.ImageData != NULL) /* Free ON-switch image data */
FreeMem(onswt_image.ImageData, (long)
(SWTGADWW * SWTGADH * SWTGADD * 2));
if(offswt_image.ImageData != NULL) /* Free OFF-switch image data */
FreeMem(offswt_image.ImageData, (long)
(SWTGADWW * SWTGADH * SWTGADD * 2));
if(IntuitionBase != NULL) /* Close Intuition library */
CloseLibrary(IntuitionBase);
exit(NULL); /* Terminate program here */
}
/* Custom assembly language input handler interface - needed for system to
* communicate with custom input handler; the system has the required
* information in registers A0 and A1. They must be placed on the stack
* with this function so the C routine (input_handler()) can pull the
* arguments off properly */
#asm
cseg
xref _input_handler
xdef _handler_interface
_handler_interface:
move.l a4,-(a7)
movem.l a0-a1,-(a7)
jsr _geta4#
jsr _input_handler
addq.l #8,a7
move.l (a7)+,a4
rts
#endasm