home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
600-699
/
ff631.lha
/
KeyBang
/
Source
/
KeyBang.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-06
|
19KB
|
661 lines
/******************************************************************************\
* KeyBang *
* ------- *
* by Mike Stark *
* Revisions: *
* 1.0 30 Mar 92 Added patterns, removed floating point math, added intro *
* window, improved input handler and added command options. *
* 0.9 23 Feb 92 Added the input handler so that keybanging would get the key *
* events before intuition. *
* 0.8 Made PAL/NTSC independent. *
* 0.7 Added the ability to play random sounds. *
* 0.? Original version (Shapes in response to intuition events) *
* Credits: *
* Michael Balzer (balzer@heike.informatik.uni-dortmund.de), the author of *
* "Bomber" for a C example of how to use the audio device. *
* Carolyn Scheppner of CATS for "OneKey" which is a concise example of how *
* to install and use an input handler. *
\******************************************************************************/
#include "KeyBang.h"
#include "table.h"
char *version = "\0$VER: KeyBang 1.0 by Mike Stark (March 30, 1992)";
#define VECTORS 30
#define CLOCK 3579545
#define FORM 0x464f524d
#define BODY 0x424f4459
#define VHDR 0x56484452
#define EIGHT_SVX 0x38535658
#define SOUNDDIRNAME "Sounds:"
extern void BabyInputHandler();
SHORT ColorTable[16] =
{
0x0000, 0x0eca, 0x0c00, 0x0f60, 0x0090, 0x03f1, 0x000f, 0x02cd, 0x0f0c,
0x0a0f, 0x0950, 0x0fe0, 0x0fff, 0x0ccc, 0x0888, 0x0444
};
#define PATTERNS 6
USHORT PatternData[] =
{
/* Solid */
0xffff,
/* Brick */
0x0101, 0x0101, 0x0101, 0xff01, 0x0101, 0x0101, 0x0101, 0x01ff,
/* Grid */
0xffff, 0x0303, 0x0303, 0x0303,
/* Diagonal lines */
0xf0f0, 0x3c3c, 0x0f0f, 0xc3c3,
/* Other diagonal lines */
0x0f0f, 0x3c3c, 0xf0f0, 0xc3c3,
/* Other brick pattern */
0x0300, 0x0300, 0x0300, 0xffff, 0x0003, 0x0003, 0x0003, 0xffff
};
struct PatternInfo
{
int Power;
USHORT *Data;
} Patterns[PATTERNS] =
{
{0, &PatternData[0]},
{3, &PatternData[1]},
{2, &PatternData[9]},
{2, &PatternData[13]},
{2, &PatternData[17]},
{3, &PatternData[21]}
};
#define MESSAGELINES 8
char *Message[] =
{
"KeyBang 1.0",
"by Mike Stark",
"March 30, 1992",
"",
"--> Alt-Alt-F5 exits <--",
"",
"This program is shareware.",
"Please read KeyBang.doc."
};
char *ScreenTitle = "KeyBang";
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Screen *BabyScreen = NULL;
struct Window *BabyWindow = NULL, *IntroWindow = NULL;
struct Remember *MemList = NULL;
BYTE *BabyTmpRaster = NULL;
APTR OldWindow;
struct IOAudio *AudioMsg = NULL;
struct MsgPort *IOReplyPort = NULL;
struct MsgPort *KeyPort = NULL;
struct IOStdReq *InputRequest = NULL;
struct Interrupt HandlerInfo;
struct SoundInfo **Sound;
int Depth = 4;
int Sounds = 0;
int HandlerData[2];
int LeftSoundPlaying = FALSE, RightSoundPlaying = FALSE;
int WinX = 640, WinY = 200, XDPM, YDPM;
int Unit[2];
BOOL Audio = FALSE, OneShape = FALSE;
main(argc, argv)
int argc;
char **argv;
{
struct MyInputEvent *Message;
struct IntuiMessage *IMessage;
struct IOAudio *SoundMsg;
int Type, XSize, YSize, X, Y, Signal, Sample, SampleUnit;
BOOL Done, DoAction, Mouse;
int Count = 0, Seed, Pattern, Colors;
GetOptions(argc, argv);
Initialize();
Colors = 1 << Depth;
Signal = 1 << KeyPort->mp_SigBit;
Signal |= 1 << IOReplyPort->mp_SigBit;
Signal |= 1 << BabyWindow->UserPort->mp_SigBit;
Done = FALSE;
while (!Done)
{
DoAction = FALSE;
Wait(Signal);
if (Audio)
while (SoundMsg = (struct IOAudio *)GetMsg(IOReplyPort))
{
SampleUnit = (int)SoundMsg->ioa_Request.io_Unit;
if (SampleUnit & 9)
RightSoundPlaying = FALSE;
if (SampleUnit & 6)
LeftSoundPlaying = FALSE;
FreeMem(SoundMsg, sizeof(struct IOAudio));
}
while (Message = (struct MyInputEvent *)GetMsg(KeyPort))
{
if (Message->IE.ie_Class == IECLASS_RAWKEY)
{
if (!((Message->IE.ie_Code & IECODE_UP_PREFIX) ||
(Message->IE.ie_Qualifier & IEQUALIFIER_REPEAT)))
{
DoAction = TRUE;
Mouse = FALSE;
}
if (Message->IE.ie_Code == 0x45)
{
Erase(BabyWindow->RPort);
}
if ((Message->IE.ie_Code == 0x54) &&
((Message->IE.ie_Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
== (IEQUALIFIER_LALT | IEQUALIFIER_RALT)))
{
DoAction = FALSE;
Done = TRUE;
}
}
FreeMem(Message, sizeof(struct MyInputEvent));
}
while (IMessage = (struct IntuiMessage *)GetMsg(BabyWindow->UserPort))
{
if (!(IMessage->Code & IECODE_UP_PREFIX))
{
Mouse = TRUE;
X = IMessage->MouseX; Y = IMessage->MouseY;
YSize = Random(0) / 505 + 10;
XSize = 2 * YSize * XDPM / YDPM;
if (X < XSize) X = XSize; if (Y < YSize) Y = YSize;
if (X > WinX - XSize) X = WinX - XSize;
if (Y > WinY - YSize) Y = WinY - YSize;
DoAction = TRUE;
}
ReplyMsg(IMessage);
}
if (DoAction)
{
if (IntroWindow)
{
CloseWindow(IntroWindow);
IntroWindow= NULL;
(void)Random(Seed);
SetDrMd(BabyWindow->RPort, JAM2);
}
if (OneShape) Erase(BabyWindow->RPort);
Sample = Random(0) * Sounds / 32768;
if (Audio) MakeSound(Sample);
if (!Mouse)
{
YSize = Random(0) / 505 + 10;
XSize = 2 * YSize * XDPM / YDPM;
Y = Random(0) * (WinY - 2 * YSize) / 32768 + YSize;
X = Random(0) * (WinX - 2 * XSize) / 32768 + XSize;
}
Pattern = Random(0) * PATTERNS / 32768;
SetAfPt(BabyWindow->RPort, Patterns[Pattern].Data, Patterns[Pattern].Power);
SetOPen(BabyWindow->RPort, Random(0) * (Colors - 1) / 32768 + 1);
SetAPen(BabyWindow->RPort, Random(0) * (Colors - 1) / 32768 + 1);
SetBPen(BabyWindow->RPort, Random(0) * (Colors - 1) / 32768 + 1);
Type = Random(0) * 5 / 32768;
switch (Type)
{
case 0:
Circle(BabyWindow->RPort, YSize, X, Y);
break;
default:
Polygon(BabyWindow->RPort, Type + 2, YSize, X, Y);
break;
}
}
}
CleanUp(FALSE);
}
Erase(RPort)
struct RastPort *RPort;
/********************\
* Erase *
* ----- *
* Clear the KeyBang window. I know that there are more efficient ways of
* doing this but this isn't too bad and that's how I coded it.
\********************/
{
Move(RPort, 0, 0);
SetDrMd(RPort, JAM1);
SetAfPt(RPort, Patterns[0].Data, Patterns[0].Power);
SetOPen(RPort, 0);
SetAPen(RPort, 0);
ClearScreen(RPort);
SetDrMd(RPort, JAM2);
}
Polygon(RPort, Vertices, Size, X, Y)
struct RastPort *RPort;
int Size, X, Y;
/********************\
* Polygon *
* ------- *
* Draw a polygon with "Vertices" vertices and "Size" pixels high centered
* at "X", "Y". Polygons are corrected for the aspect ratio of the screen. The
* AreaInfo and TmpRas structures of the window into which the polygon is to
* be drawn must be properly initialized. See Initialize.
\********************/
{
int Phase, XPos, YPos, i;
Phase = Random(0) * SINETABENTRIES / 32768;
XPos = Size * SineTab[Phase] / 128;
YPos = Size * SineTab[(Phase + SINETABENTRIES / 4) % SINETABENTRIES] / 128;
AreaMove(RPort, X + 2 * XPos * XDPM / YDPM, Y + YPos);
for (i = 1; i < Vertices; i++)
{
XPos = Size * SineTab[(i * SINETABENTRIES / Vertices + Phase)
% SINETABENTRIES] / 128;
YPos = Size * SineTab[(i * SINETABENTRIES / Vertices + Phase +
SINETABENTRIES / 4) % SINETABENTRIES] / 128;
AreaDraw(RPort, X + 2 * XDPM * XPos / YDPM, Y + YPos);
}
AreaEnd(RPort);
}
int Circle(RPort, Size, X, Y)
struct RastPort *RPort;
int Size, X, Y;
/********************\
* Circle *
* ------ *
* Draw a circle "Size" pixels high centered at "X", "Y". Circles are
* corrected for the aspect ratio of the screen. The AreaInfo and TmpRas
* structures of the window into which the circle is to be drawn must be
* properly initialized. See Initialize.
\********************/
{
AreaEllipse(RPort, X, Y, 2 * Size * XDPM / YDPM, Size);
AreaEnd(RPort);
}
Initialize()
/********************\
* Initialize *
* ---------- *
* Allocates all of the resources that are used by the program. If some
* of the resources are not available, this routine does not return.
\********************/
{
struct NewWindow NewWindow;
struct NewScreen NewScreen;
SHORT *VectorTable;
static UBYTE AudioChannels[] = {3, 5, 10, 12};
extern struct Library *SysBase;
int i, Width, Length;
struct Process *ThisProcess;
/* Open libraries */
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 29);
if (IntuitionBase == NULL)
CleanUp(FALSE);
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 29);
if (GfxBase == NULL)
CleanUp(FALSE);
/* Get display size and aspect ratio from GfxBase */
XDPM = GfxBase->NormalDPMX;
YDPM = GfxBase->NormalDPMY;
WinX = GfxBase->NormalDisplayColumns;
WinY = GfxBase->NormalDisplayRows;
/* Open the screen */
NewScreen.LeftEdge = 0;
NewScreen.TopEdge = 0;
NewScreen.Width = WinX;
NewScreen.Height = WinY;
NewScreen.Depth = Depth;
NewScreen.DetailPen = 1;
NewScreen.BlockPen = 1;
NewScreen.ViewModes = HIRES;
NewScreen.Type = CUSTOMSCREEN;
NewScreen.Font = NULL;
NewScreen.DefaultTitle = (UBYTE *)ScreenTitle;
NewScreen.Gadgets = NULL;
NewScreen.CustomBitMap = NULL;
if ((BabyScreen = (struct Screen *)OpenScreen(&NewScreen)) == NULL)
CleanUp(FALSE);
/* Open the window */
NewWindow.LeftEdge = 0;
NewWindow.TopEdge = 0;
NewWindow.Width = WinX;
NewWindow.Height = WinY;
NewWindow.DetailPen = 1;
NewWindow.BlockPen = 1;
NewWindow.IDCMPFlags = MOUSEBUTTONS;
NewWindow.Flags = SIMPLE_REFRESH | BORDERLESS | ACTIVATE | BACKDROP | RMBTRAP;
NewWindow.FirstGadget = NULL;
NewWindow.CheckMark = NULL;
NewWindow.Title = NULL;
NewWindow.Screen = BabyScreen;
NewWindow.BitMap = NULL;
NewWindow.MinWidth = WinX;
NewWindow.MinHeight = WinY;
NewWindow.MaxWidth = WinX;
NewWindow.MaxHeight = WinY;
NewWindow.Type = CUSTOMSCREEN;
LoadRGB4(&BabyScreen->ViewPort, &ColorTable[0], 1 << Depth);
if ((BabyWindow = (struct Window *)OpenWindow(&NewWindow)) == NULL)
CleanUp(FALSE);
/* Make system requexters come up on this screen */
ThisProcess = (struct Process *)FindTask(0);
OldWindow = ThisProcess->pr_WindowPtr;
ThisProcess->pr_WindowPtr = (APTR)BabyWindow;
/* Hide the screen title bar */
ShowTitle(BabyScreen, FALSE);
/* Open the message window */
Width = 0;
for (i = 0; i < MESSAGELINES; i++)
{
Length = TextLength(BabyWindow->RPort, Message[i], strlen(Message[i]));
if (Length + 16 > Width) Width = Length + 16;
}
NewWindow.LeftEdge = WinX / 2 - Width / 2;
NewWindow.TopEdge = 30;
NewWindow.Width = Width;
NewWindow.Height = 100;
NewWindow.IDCMPFlags = NULL;
NewWindow.Flags = SIMPLE_REFRESH;
NewWindow.Title = (UBYTE *)ScreenTitle;
NewWindow.MinWidth = Width;
NewWindow.MinHeight = 100;
NewWindow.MaxWidth = Width;
NewWindow.MaxHeight = 100;
if (IntroWindow = (struct Window *)OpenWindow(&NewWindow))
{
SetAPen(IntroWindow->RPort, 1);
for (i = 0; i < MESSAGELINES; i++)
{
Length = TextLength(IntroWindow->RPort, Message[i], strlen(Message[i]));
Move(IntroWindow->RPort, Width / 2 - Length / 2, 20 + 10 * i);
Text(IntroWindow->RPort, Message[i], strlen(Message[i]));
}
}
/* Open the AreaInfo and TmpRas structures used by the drawing routines */
BabyWindow->RPort->TmpRas =
(struct TmpRas *)AllocRemember(&MemList, sizeof(struct TmpRas), NULL);
if (!BabyWindow->RPort->TmpRas)
CleanUp(FALSE);
if (!(BabyTmpRaster = AllocRaster(WinX, WinY)))
CleanUp(FALSE);
InitTmpRas(BabyWindow->RPort->TmpRas, BabyTmpRaster, RASSIZE(WinX, WinY));
BabyWindow->RPort->AreaInfo =
(struct AreaInfo *)AllocRemember(&MemList, sizeof(struct AreaInfo), NULL);
if (!BabyWindow->RPort->AreaInfo)
CleanUp(FALSE);
if ((VectorTable = (SHORT *)AllocRemember(&MemList, VECTORS * 5, NULL))== NULL)
CleanUp(FALSE);
InitArea(BabyWindow->RPort->AreaInfo, VectorTable, VECTORS);
/* Make the IO reply port for audio and input IO */
if ((IOReplyPort = CreatePort("KeyBangIO", 0)) == NULL)
CleanUp(FALSE);
/* Make the port to receive messages from the input handler */
if ((KeyPort = CreatePort("KeyBangKeys", 0)) == NULL)
CleanUp(FALSE);
/* Open the audio device */
LoadSounds();
if (Sounds)
{
AudioMsg = (struct IOAudio *)AllocRemember(&MemList, sizeof(struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR);
if (AudioMsg == NULL)
CleanUp(FALSE);
AudioMsg->ioa_Request.io_Message.mn_ReplyPort = IOReplyPort;
AudioMsg->ioa_Request.io_Command = ADCMD_ALLOCATE;
AudioMsg->ioa_Request.io_Flags = ADIOF_NOWAIT;
AudioMsg->ioa_Data = AudioChannels;
AudioMsg->ioa_Length = sizeof(AudioChannels);
if (OpenDevice(AUDIONAME, 0 , AudioMsg, 0) == 0)
{
Audio = TRUE;
Unit[0] = (int)AudioMsg->ioa_Request.io_Unit & 9;
Unit[1] = (int)AudioMsg->ioa_Request.io_Unit & 6;
}
}
/* Open the input device and install the input handler */
if (!(InputRequest = CreateStdIO(IOReplyPort)))
CleanUp(FALSE);
if (OpenDevice("input.device", 0, InputRequest, 0))
CleanUp(FALSE);
HandlerData[0] = (int)KeyPort;
HandlerData[1] = (int)SysBase;
HandlerInfo.is_Data = (APTR)&HandlerData[0];
HandlerInfo.is_Code = BabyInputHandler;
HandlerInfo.is_Node.ln_Name = ScreenTitle;
HandlerInfo.is_Node.ln_Pri = 75;
InputRequest->io_Command = IND_ADDHANDLER;
InputRequest->io_Data = (APTR)&HandlerInfo;
DoIO(InputRequest);
}
LoadSounds()
/********************\
* LoadSounds *
* ---------- *
* Look into the sound directory and examine all the files. Those which
* contain IFF 8SVX samples are loaded into an array so that they can be
* played by MakeSound.
\********************/
{
int SoundLength;
struct FileLock *SoundLock;
struct FileInfoBlock *FileInfoBlock;
struct FileHandle *File;
UBYTE *Buffer;
char FileName[128];
struct IFFHeader Header;
struct SampleInfo SampleInfo;
Sound = (struct SoundInfo **)AllocRemember(&MemList, 100 * 4, NULL);
SoundLock = Lock(SOUNDDIRNAME, ACCESS_READ);
if (!SoundLock)
return;
FileInfoBlock = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock), NULL);
Examine(SoundLock, FileInfoBlock);
while (ExNext(SoundLock, FileInfoBlock))
{
strcpy(FileName, SOUNDDIRNAME);
strcat(FileName, FileInfoBlock->fib_FileName);
File = Open(FileName, MODE_OLDFILE);
if (File)
{
Read(File, &Header, 8);
if (Header.Name == FORM)
{
Read(File, &Header, 4);
if (Header.Name == EIGHT_SVX)
{
while (Read(File, &Header, 8) > 0)
{
switch (Header.Name)
{
case VHDR:
Read(File, &SampleInfo, Header.Length);
break;
case BODY:
Buffer = (UBYTE *)AllocRemember(&MemList, Header.Length,
MEMF_CHIP | MEMF_PUBLIC);
if (!Buffer) return;
Read(File, Buffer, Header.Length);
SoundLength = Header.Length;
break;
default:
Seek(File, Header.Length, OFFSET_CURRENT);
break;
}
}
Sound[Sounds] =(struct SoundInfo *)AllocRemember(&MemList,
sizeof(struct SoundInfo), NULL);
if (!Sound[Sounds]) CleanUp(FALSE);
Sound[Sounds]->Buffer = Buffer;
Sound[Sounds]->SamplePeriod = CLOCK / SampleInfo.SampleRate;
Sound[Sounds]->Volume = SampleInfo.Volume / 1024;
Sound[Sounds]->Length = SoundLength;
Sounds++;
}
}
}
Close(File);
}
UnLock(SoundLock);
FreeMem(FileInfoBlock, sizeof(struct FileInfoBlock));
}
MakeSound(Sample)
int Sample;
/********************\
* MakeSound *
* --------- *
* Play the sound "Sample". "Sample" is an index into the array of
* sound samples loaded by LoadSounds. If one of the two channels opened by
* KeyBang are busy, the sound is played in the other. If both are busy,
* no sound is played.
\********************/
{
BYTE *SoundData;
struct IOAudio *SoundMsg;
int i;
static int UnitNum;
if (LeftSoundPlaying)
{
if (RightSoundPlaying)
return;
else
UnitNum = 0;
}
else
{
if (RightSoundPlaying)
UnitNum = 1;
else
UnitNum = UnitNum - 2 * UnitNum + 1;
}
if (SoundMsg = (struct IOAudio *)AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC))
{
SoundMsg->ioa_Request.io_Message.mn_ReplyPort = IOReplyPort;
SoundMsg->ioa_Request.io_Device = AudioMsg->ioa_Request.io_Device;
SoundMsg->ioa_Request.io_Unit = (struct Unit *)Unit[UnitNum];
SoundMsg->ioa_Request.io_Command = CMD_WRITE;
SoundMsg->ioa_Request.io_Flags = ADIOF_PERVOL;
SoundMsg->ioa_AllocKey = AudioMsg->ioa_AllocKey;
SoundMsg->ioa_Length = Sound[Sample]->Length;
SoundMsg->ioa_Period = Sound[Sample]->SamplePeriod;
SoundMsg->ioa_Volume = 64;
SoundMsg->ioa_Cycles = 1;
SoundMsg->ioa_Data = Sound[Sample]->Buffer;
BeginIO(SoundMsg);
if (Unit[UnitNum] & 9)
RightSoundPlaying = TRUE;
if (Unit[UnitNum] & 6)
LeftSoundPlaying = TRUE;
}
}
CleanUp(Flag)
BOOL Flag;
/********************\
* CleanUp *
* ------- *
* Deallocate all resources. I have tried to reply to all messages
* which may be waiting on ports before deleting them.
\********************/
{
struct Message *TempPointer;
struct Process *ThisProcess;
if (Flag)
puts("Usage : KeyBang [-colors {2|4|8|16}] [-oneshape]");
if (InputRequest)
{
InputRequest->io_Command = IND_REMHANDLER;
InputRequest->io_Data = (APTR)&HandlerInfo;
DoIO(InputRequest);
CloseDevice(InputRequest);
DeleteStdIO(InputRequest);
}
if (Audio) CloseDevice(AudioMsg);
if (IOReplyPort)
DeletePort(IOReplyPort);
if (KeyPort)
{
while (TempPointer = GetMsg(KeyPort))
FreeMem(TempPointer, sizeof(struct MyInputEvent));
DeletePort(KeyPort);
}
if (BabyTmpRaster) FreeRaster(BabyTmpRaster, WinX, WinY);
if (IntroWindow) CloseWindow(IntroWindow);
if (BabyWindow)
{
ThisProcess = (struct Process *)FindTask(0);
ThisProcess->pr_WindowPtr = OldWindow;
CloseWindow(BabyWindow);
}
if (BabyScreen) CloseScreen(BabyScreen);
if (MemList) FreeRemember(&MemList, TRUE);
if (GfxBase) CloseLibrary(GfxBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
exit(0);
}
int Random(UserSeed)
unsigned long int UserSeed;
{
static unsigned long int Seed;
if (UserSeed) Seed = UserSeed;
Seed = Seed * 1103515245 + 12345;
return (unsigned int)(Seed/65536) % 32768;
}