// =============================================================================
// KEYQUENCER EXTENSIONS HEADER - VERSION 1.2.1 - NOVEMBER 1994
// ©1994 Alessandro Levi Montalcini <LMontalcini@pmn.it>
// DonŐt forget to send me any cool extensions you create!
// This text looks best in monaco 9 font, 4 spaces per tab, no wrapping

#ifndef _H_extension
#define _H_extension

#ifndef __APPLEEVENTS__
#include <AppleEvents.h>
#endif

#if defined(powerc) || defined (__powerc)
#pragma options align=mac68k
#endif

// =============================================================================
// FORMAT OF THE MAIN ROUTINE FOR A KEYQUENCER EXTENSION:
// (the procedure pointer type is defined below after the record declarations)

// pascal short main(long message, ParamsPtr params, MachineHandle mac, GluePtr glue);

// =============================================================================
// CONSTANTS AND RESOURCE TYPES:

#define kExtensionResType 'KQex'	//  the extension res name (not file name)
									//  is used by the macro interpreter
#define kExtensionFileType 'KQex'	//  extension file type
#define kExtensionCreator 'KQue'	//  extension file creator (standard icon)
#define kMaxExtParams 32			//  max # of parameters passed to an extension
#define kMaxScreens 3				//  max # of screens in the MachineRec record

// =============================================================================
// MESSAGES (sent to the extension):

enum {
	kExtMessageInit	= 'INIT',		//  setup extension, load resources;
									//  no ParamsPtr available here
	kExtMessageRun	= 'RUN '		//  run extension; the extension resource file
									//  is already closed
};

// WARNING: GLUE WAS NOT AVAILABLE AT INITIALIZE TIME IN KEYQUENCER 1.0 (now it is)
// Check for nil glue before using glue routines in your kExtMessageInit handler

// =============================================================================
// RESULT CODES (returned by the extension):

enum {
	kExtNoError = 0,				//  no error
	kExtCallMeAgain,				//  keep calling the extension over and over
	kExtCallMeAgainLater,			//  call the extension again after all other
									//  queued commands have executed
	kExtGenericError = 256,			//  positive results >= 256 stop macro execution
	kExtBadEnvironment,				//  without informing the user (you may use
	kExtBadParameters,				//  DisplayMessage or DisplayError to do so)
	kExtTooManyParams,
	kExtNotEnoughParams,
	kExtUnknownKeyword,
	kExtWrongApplication,
	kExtNotEnoughMemory,
	kExtObsoleteKeyQuencer,
	kExtRequiresAppleEvents,
	
	kTellGenericError = -256,		//  negative results stop macro execution
	kTellBadEnvironment,			//  and show a standard error message
	kTellBadParameters,
	kTellTooManyParams,
	kTellNotEnoughParams,
	kTellUnknownKeyword,
	kTellWrongApplication,
	kTellNotEnoughMemory,
	kTellObsoleteKeyQuencer,
	kTellRequiresAppleEvents
};

// =============================================================================
// CURRENT RECORD VERSIONS (will increase as I append more items to the records):

enum {
	kCurParamsRecVers	= 1,
	kCurMachineRecVers	= 1,
	kCurGlueRecVers		= 3,		//  version 1 had 13 callbacks, v. 2 had 19
	kCurRoutineCount	= 27		//  number of callback routines in the glue
};

// =============================================================================
// RECORD DEFINITIONS:
// The current record contents will not be modified in future versions
// although more items may be appended at the bottom of each record

typedef struct ParamsRec {
	short		paramsRecVers;				//  kCurParamsRecVers
	short		paramsCount;				//  number of parameters passed
	long		countCalls;					//  this field is initially set to 0,
											//  incremented at each kExtCallMeAgain,
											//  always 1 after kExtCallMeAgainLater
	long		firstCallTicks;				//  TickCount() of first time called
											//  (reset when result != kExtCallMeAgain)
	short		extensionKey;				//  keyCode<<8 + charCode (low word of
											//  event.message of key down event)
	short		extensionModifiers;			//  event.modifiers of the key down event
											//  that invoked the macro
	long		reserved;					//  don't touch this!
	StringPtr	parameter[kMaxExtParams];	//  parameters are passed as read-only
											//  pascal strings (including quotes if any);
											//  all parameter processing is done by
											//  the extension itself
} ParamsRec, *ParamsPtr;

typedef struct MachineRec {
	short		machineRecVers;				//  kCurMachineRecVers
	short		systemVersion;				//  system version in BCD format
	short		screenCount;				//  # of screens connected to this machine
	short		mainScreen;					//  index of main screen in screenBounds array
	Rect		screenBounds[kMaxScreens];	//  bounds of all available screens
											//  (call UpdateMachineRec to validate bounds)
	Boolean		hasGestalt;					//  01
	Boolean		hasWaitNextEvent;			//  02
	Boolean		hasAppleEvents;				//  03
	Boolean		has68020;					//  04
	Boolean		hasFPU;						//  05
	Boolean		hasColorQD;					//  06  all these flags are automatically
	Boolean		has32BitQD;					//  07  set up by KeyQuencer so the extensions
	Boolean		hasFSSpec;					//  08  don't have to call Gestalt all the time
	Boolean		hasNewStdFile;				//  09
	Boolean		hasNotification;			//  10
	Boolean		hasAliases;					//  11
	Boolean		hasFindFolder;				//  12
	Boolean		hasPartialRes;				//  13
	Boolean		hasSoundManager;			//  14
} MachineRec, *MachinePtr, **MachineHandle;

typedef struct GlueRec {
	short				glueRecVers;			// check before using recent callbacks
	short				routineCount;			// don't check this
	pascal void			(*DisplayMessage)		(ConstStr255Param message, Boolean playBeep);
	pascal void			(*DisplayError)			(OSErr error);
	pascal void			(*StopSequence)			(void);
	pascal void			(*TypeString)			(ConstStr255Param string);
	pascal void			(*TypeText)				(const unsigned char *text, short length);
	pascal Boolean		(*SafePostEvent)		(const EventRecord *event);
	pascal void			(*WaitTicks)			(long pause);
	pascal short		(*ExecuteScript)		(Handle text);
	pascal Boolean		(*ExtensionAvailable)	(ConstStr255Param name);
	pascal void			(*GetCharacterInfo)		(unsigned char c, short *message, short *modifiers);
	pascal Boolean		(*TrapAvailable)		(short trap);
	pascal void			(*ShowStartupIcon)		(short iconID);
	pascal void			(*AnonymousMessage)		(ConstStr255Param message, Boolean playBeep);
	
// the following routines are only available in glue version 2 or later (KQ 1.1 or later);
// make sure that glue->glueRecVers >= 2 before using them:
	
	pascal Boolean		(*AppleEventsAvail)		(void);
	pascal Boolean		(*SendAppleEvent)		(const AppleEvent *event, OSErr *errPtr, Boolean bringToFront);
	pascal Boolean		(*WindowsAvailable)		(void);
	pascal Boolean		(*MacroRunning)			(void);
	pascal Boolean		(*EqualStringPartial)	(ConstStr255Param strToFind, ConstStr255Param strToSearch, Boolean caseSens, Boolean partialMatch);
	pascal long			(*SearchString)			(ConstStr255Param strToFind, const unsigned char *buffer, long size, Boolean caseSens);

// the following routines are only available in glue version 3 or later (KQ 1.2 or later);
// make sure that glue->glueRecVers >= 3 before using them:
	
	pascal WindowPtr	(*RealFrontWindow)		(Boolean *isModalDialog);
	pascal WindowPtr	(*RealNextWindow)		(WindowPtr baseWindow, Boolean *isModalDialog);
	pascal Boolean		(*RealWindow)			(WindowPtr window, Boolean *isModalDialog);
	pascal OSErr		(*FindKQExtFolder)		(short *vRefNum, long *dirID);
	pascal short		(*OpenExtResFile)		(void);
	pascal void			(*UpdateMachineRec)		(void);
	pascal Boolean		(*AskQuestion)			(ConstStr255Param question, ConstStr255Param okButtonTitle, ConstStr255Param cancelButtonTitle, short defaultButton, short numTextLines);
	pascal Boolean		(*AskString)			(ConstStr255Param question, StringPtr answer, ConstStr255Param okButtonTitle, ConstStr255Param cancelButtonTitle, short defaultButton, short numInputLines);

} GlueRec, *GluePtr;

// =============================================================================
// GLUE - QUICK REFERENCE:
/*
DisplayMessage:		displays a message (pascal string) via the notification mgr,
					optionally plays a system beep
DisplayError:		displays an error (common OSErr's are shown by name in KQ 1.2)
StopSequence:		stops all macros and flushes the queue (same as cmd-shift-return)
TypeString:			types a pascal string as if the user was typing it from the keyboard
TypeText:			same as TypeString, takes a buffer instead of a pascal string
SafePostEvent:		checks the event queue and posts an event if it isn't already full
					(use this instead of PPostEvent); returns true if everything OK
WaitTicks:			pauses macro execution for some time after the extension has returned
ExecuteScript:		executes a macro (the macro text is passed in a handle);
					returns 0 if the macro was successfully queued,
					nonzero if an error was found (this is an internal error code)
ExtensionAvailable:	checks if an extension was loaded at startup
GetCharacterInfo:	returns the keyCode, charCode and modifiers needed to type
					a given character with a keyDown event
TrapAvailable:		checks if a trap is available (returns true if it is, false otherwise)
ShowStartupIcon:	displays a startup icon (this only works at startup time,
					when the init message is received by the extension)
AnonymousMessage:	displays a message (pascal string) without the extension name

// the following routines are only available in glue version 2 or later (KQ 1.1 or later);
// make sure that glue->glueRecVers >= 2 before using them:

AppleEventsAvail:	returns true if KQ Apple Events is running, false otherwise;
					SendAppleEvent can do without KQ Apple Events under KQ 1.2 or later
SendAppleEvent:		sends an Apple Event; the AppleEvent record is duplicated so it can
					be allocated on the stack, while the event data handle must be in
					the system zone and is disposed of automatically by SendAppleEvent;
					never call AEDisposeDesc on the AppleEvent after passing it to
					SendAppleEvent, since it's already called by KeyQuencer for you;
					*errPtr is set to 1 right away, and receives the error code when
					the event is later sent (pass nil if you don't care, but don't wait
					for this value to change inside a loop because KQ Apple Events will
					wait and send the event when it gets some CPU time at WaitNextEvent);
					if bringToFront is true, the receiving application is switched to
					the foreground before the event is sent; SendAppleEvent returns
					true if the event was successfully queued (not sent), false otherwise
WindowsAvailable:	returns true if QuickDraw and the Window Manager have been initialized
MacroRunning:		returns true if KeyQuencer has more extensions to call or keystrokes
					to type inside its internal queues
EqualStringPartial:	compares two strings with optional case sensitivity and partial
					matching (strToFind is a subset of strToSearch); returns true if equal
SearchString:		searches a string inside a buffer with optional case sensitivity;
					returns the offset of the first matching character, or a negative
					number if no match was found

// the following routines are only available in glue version 3 or later (KQ 1.2 or later);
// make sure that glue->glueRecVers >= 3 before using them:

RealFrontWindow:	returns the frontmost "real" window (uses RealWindow to filter
					out weird windows and floating palettes)
RealNextWindow:		returns the next "real" window behind a given base window
RealWindow:			returns false for floating palettes, the desktop and other weird
					windows (this is an educated guess, not 100% reliable)
FindKQExtFolder:	finds the volume reference number and directory ID of the
					"KeyQuencer Extensions" folder
OpenExtResFile:		opens the extension resource file; please don't use this if you can
					do without, since PowerBook users hate to have the HD spin up
					(the opened file is NOT guaranteed to be the same file that was
					loaded at startup: it may be an updated version, or another file
					with the same name that was copied into the "KeyQuencer Extensions"
					folder); returns refnum of resfile, or -1 if the file can't be opened
UpdateMachineRec:	updates the machine record (the screen information fields may change
					after startup with the new Multiple Scan monitors)
AskQuestion:		displays an ok/cancel dialog and returns true if the "ok" button was
					pressed; returns false when the user cancels and when an error occurs;
					pass nil or an empty string to get the default button titles
AskString:			displays a dialog with an editable text whose contents are copied
					from and passed back to the "answer" parameter; returns the same
					values you get from AskQuestion
*/
// =============================================================================
// EXTENSION PROCEDURE POINTER TYPE DEFINITION:

typedef pascal short (*ExtProcPtr)(long message, ParamsPtr params, MachineHandle mac, GluePtr glue);

// =============================================================================

#if defined(powerc) || defined(__powerc)
#pragma options align=reset
#endif

#endif	// _H_extension

// =============================================================================
