home *** CD-ROM | disk | FTP | other *** search
- /* 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
-
-