		/********************************
		 *   Function Keys 1.1  03/89   *
		 *     by Torsten Jürgeleit     *
		 *    for Manx Aztec C v3.6a    *
		 *      cc fkeys                *
		 *      ln fkeys detach -lc     *
		 ********************************/

	/* Includes */

#include <exec/exec.h>
#include <devices/input.h>
#include <libraries/dos.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <functions.h>

	/* Defines */

#define WINDOW_WIDTH	280
#define WINDOW_HEIGHT	180
#define GADGET_REMOVE	0
#define GADGET_CONTINUE	1

#define NEWCLI		"NewCLI >NIL: <NIL:"	/* "NewWSH >NIL: <NIL:" */
#define SIGB_ACTION	((ULONG)((struct MsgPort *)main_task)->mp_SigBit)
#define SIGF_ACTION	(1L << SIGB_ACTION)

#define ACTION_NOTHING			0
#define ACTION_NEWCLI			1
#define ACTION_REMOVE_REQUESTER		2

	/* Declarations for DETACH (segment list splitting) */

LONG _stack        = 0x1000;
LONG _priority     = 0;
LONG _BackGroundIO = 0;
BYTE *_procname    = "FKeys1.1";

	/* Globals */

struct GfxBase		*GfxBase;
struct IntuitionBase	*IntuitionBase;
struct LayersBase	*LayersBase;
struct Task		*main_task;
struct FileHandle	*file_handle;
struct MsgPort		*input_port;
struct IOStdReq		*input_req;
struct Interrupt	interrupt;
UBYTE action = ACTION_NOTHING;

	/* Dummy functions - not used from c.lib */

VOID _cli_parse() {}
VOID _wb_parse() {}

	/* Casts */

VOID interrupt_server(), back_window_to_front(), front_window_to_back(),
     activate_next_window(), activate_previous_window(),
     active_window_to_front(), active_window_to_back(), quit_program(),
     back_screen_to_front(), front_screen_to_back(), newcli();
BOOL remove_requester();
struct Window  *top_window(), *bottom_window(), *next_window(),
	       *previous_window();

	/* Main - installs interrupt server and performs interrupt action */

   VOID
main()
{
   BOOL remove = FALSE;

   main_task = FindTask(NULL);
   if (file_handle = Open("NIL:", MODE_NEWFILE)) {
      if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) {
	 if (IntuitionBase = (struct IntuitionBase *)
				     OpenLibrary("intuition.library", 0L)) {
	    if (FindPort(_procname)) {
	       DisplayBeep(NULL);
	    } else {
	       if (LayersBase = (struct LayersBase *)
					OpenLibrary("layers.library", 0L)) {
		  if (input_port = CreatePort(_procname, 0L)) {
		     if (input_req = CreateStdIO(input_port)) {
			if (! OpenDevice("input.device", 0L, input_req,
								      0L)) {
			   interrupt.is_Code         = (VOID (*)())
							  &interrupt_server;
			   interrupt.is_Data         = NULL;
			   interrupt.is_Node.ln_Name = _procname;
			   interrupt.is_Node.ln_Pri  = 51;   /* above of Intuition */
			   input_req->io_Command     = IND_ADDHANDLER;
			   input_req->io_Data        = (APTR)&interrupt;
			   if (! DoIO(input_req)) {
			      do {
				 Wait(SIGF_ACTION);   /* wait for action signal */
				 switch (action) {
				    case ACTION_NEWCLI :
				       if (WBenchToFront() == FALSE) {
					  DisplayBeep(NULL);
				       } else {
					  Execute(NEWCLI, file_handle,
							       file_handle);
				       }
				       break;
				    case ACTION_REMOVE_REQUESTER :
				       remove = remove_requester();
				       break;
				 }
			      } while (remove != TRUE);
			      input_req->io_Command = IND_REMHANDLER;
			      DoIO(input_req);
			      DisplayBeep(NULL);
			   }
			   CloseDevice(input_req);
			}
			DeleteStdIO(input_req);
		     }
		     DeletePort(input_port);
		  }
		  CloseLibrary(LayersBase);
	       }
	    }
	    CloseLibrary(IntuitionBase);
	 }
	 CloseLibrary(GfxBase);
      }
      Close(file_handle);
   }
}
	/* Interrupt server to parse event list for function key events */

   VOID
interrupt_server()
{
#asm
IECLASS_NULL			EQU	$00
IECLASS_RAWKEY			EQU	$01
IECODEB_KEYUP			EQU	7
IECODE_F1KEY			EQU	$50
IEQUALIFIERB_REPEAT		EQU	9
IEQUALIFIER_CAPSLOCK		EQU	$0004
IEQUALIFIER_LCOMMAND		EQU	$0040
IEQUALIFIER_REPEAT		EQU	$0200
IEQUALIFIER_RELATIVEMOUSE	EQU	$8000
ie_NextEvent			EQU	$00	; APTR
ie_Class			EQU	$04	; UBYTE
ie_Code				EQU	$06	; UWORD
ie_Qualifier			EQU	$08	; UWORD

	XREF	_geta4#
	XREF	_function_table

	; (called with :  a0 = event list ptr  ,  a1 = interrupt data ptr)
	movem.l	a0-a6/d0-d7,-(sp)
	jsr	_geta4#		; Aztec C need it for small code/data model
	bra.s	check_next_event

event_loop:
	cmp.b	#IECLASS_RAWKEY,ie_Class(a0)	; check ie_Class
	bne.s	next_event
	move.w	ie_Qualifier(a0),d0		; check ie_Qualifier
	move.w	d0,d1				; save ie_Qualifier
	and.w	#~(IEQUALIFIER_RELATIVEMOUSE|IEQUALIFIER_CAPSLOCK|IEQUALIFIER_REPEAT),d0
	cmp.w	#IEQUALIFIER_LCOMMAND,d0	; left Amiga key pressed ?
	bne.s	next_event
	move.w	ie_Code(a0),d0			; check ie_Code
	btst	#IECODEB_KEYUP,d0		; only key down events
	bne.s	next_event
	sub.w	#IECODE_F1KEY,d0		; function key pressed ?
	cmp.w	#10,d0
	bcc.s	next_event
	btst	#IEQUALIFIERB_REPEAT,d1		; ignore auto repeat
	bne.s	clear_event

fkey_pressed:
	lsl.w	#2,d0
	lea	_function_table,a1
	move.l	(a1,d0.w),a1			; a1 := function ptr
	move.l	a0,-(sp)			; save event ptr
	jsr	(a1)				; call function
	move.l	(sp)+,a0			; restore event ptr

clear_event:
	move.l	#IECLASS_NULL,ie_Class(a0)	; clear event
	
next_event:
	move.l	ie_NextEvent(a0),a0		; get next event in list

check_next_event:
	move.l	a0,d0				; next event ptr == NULL ?
	bne.s	event_loop

	movem.l	(sp)+,a0-a6/d0-d7
	move.l	a0,d0				; return event list ptr
#endasm
}
	/* Remove and about requester */

struct TextAttr  topaz80 = { (STRPTR)"topaz.font", TOPAZ_EIGHTY, 0, 0 };
struct TextAttr  topaz60 = { (STRPTR)"topaz.font", TOPAZ_SIXTY, 0, 0 };

SHORT border_vec[] = {0, 0, 81, 0, 81, 21, 0, 21, 0, 0 };
struct Border  border = { -1, -1, 0, 0, JAM1, 5, &border_vec[0], NULL };

struct IntuiText  remove_text = { 3, 0, JAM1, 16, 6, &topaz80, (UBYTE *)
   "Remove", NULL };
struct Gadget remove_gadget = { NULL, 20, WINDOW_HEIGHT - 30, 80, 20,
   GADGHCOMP, RELVERIFY, BOOLGADGET, (APTR)&border, NULL, &remove_text, 0,
   NULL, GADGET_REMOVE, NULL};
struct IntuiText  continue_text = { 3, 0, JAM1, 8, 6, &topaz80, (UBYTE *)
   "Continue", NULL };
struct Gadget continue_gadget = { &remove_gadget, WINDOW_WIDTH - 100,
   WINDOW_HEIGHT - 30, 80, 20, GADGHCOMP, RELVERIFY, BOOLGADGET, (APTR)
   &border, NULL, &continue_text, 0, NULL, GADGET_CONTINUE, NULL};

struct IntuiText  usage_text10 = { 2, 0, JAM1, 20, 135, &topaz80, (UBYTE *)
   "F10 : show this window", NULL };
struct IntuiText  usage_text9 = { 2, 0, JAM1, 20, 125, &topaz80, (UBYTE *)
   "F9  : open NewCLI window"   /* "F9  : open NewWSH window"*/,
   &usage_text10 };
struct IntuiText  usage_text8 = { 2, 0, JAM1, 20, 115, &topaz80, (UBYTE *)
   "F8  : front screen to back", &usage_text9 };
struct IntuiText  usage_text7 = { 2, 0, JAM1, 20, 105, &topaz80, (UBYTE *)
   "F7  : back screen to front", &usage_text8 };
struct IntuiText  usage_text6 = { 2, 0, JAM1, 20, 95, &topaz80, (UBYTE *)
   "F6  : active window to back", &usage_text7 };
struct IntuiText  usage_text5 = { 2, 0, JAM1, 20, 85, &topaz80, (UBYTE *)
   "F5  : active window to front", &usage_text6 };
struct IntuiText  usage_text4 = { 2, 0, JAM1, 20, 75, &topaz80, (UBYTE *)
   "F4  : activate previous window", &usage_text5 };
struct IntuiText  usage_text3 = { 2, 0, JAM1, 20, 65, &topaz80, (UBYTE *)
   "F3  : activate next window", &usage_text4 };
struct IntuiText  usage_text2 = { 2, 0, JAM1, 20, 55, &topaz80, (UBYTE *)
   "F2  : front window to back", &usage_text3 };
struct IntuiText  usage_text1 = { 2, 0, JAM1, 20, 45, &topaz80, (UBYTE *)
   "F1  : back window to front", &usage_text2 };
struct IntuiText  title_text2 = { 3, 0, JAM1, WINDOW_WIDTH / 2 - 20 * 4, 30,
   &topaz80, (UBYTE *)"by Torsten Jürgeleit", &usage_text1 };
struct IntuiText  title_text1 = { 0, 0, JAM1, WINDOW_WIDTH / 2 - 17 * 5, 18,
   &topaz60, (UBYTE *)"FKeys v1.1  03/89", &title_text2 };

struct NewWindow  new_window = { 320 - WINDOW_WIDTH / 2, 100 - WINDOW_HEIGHT
   / 2, WINDOW_WIDTH, WINDOW_HEIGHT, 2, 3, GADGETUP, WINDOWDEPTH |
   WINDOWDRAG | ACTIVATE | SMART_REFRESH | RMBTRAP, NULL, NULL, (UBYTE *)
   " FKeys ", NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN };

/******/

   BOOL
remove_requester()
{
   struct Window	*window;
   struct IntuiMessage	*msg;
   struct Gadget	*gad;
   LONG  class;
   BOOL  remove = FALSE, exit = FALSE;

   if ((window = OpenWindow(&new_window)) == NULL) {
      DisplayBeep(NULL);
      remove = TRUE;
   } else {
      SetAPen(window->RPort, 1L);
      RectFill(window->RPort, 5L, 12L, WINDOW_WIDTH - 7L, WINDOW_HEIGHT -
									4L);
      PrintIText(window->RPort, &title_text1, 0L, 0L);
      AddGList(window, &continue_gadget, -1L, -1L, NULL);
      RefreshGadgets(&continue_gadget, window, NULL);
      do {
	 WaitPort(window->UserPort);
	 while (msg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
	    class = msg->Class;
	    gad   = (struct Gadget *)msg->IAddress;
	    ReplyMsg(msg);
	    if (class == GADGETUP) {
	       if (gad->GadgetID == GADGET_REMOVE) {
		  remove = TRUE;
	       }
	       exit = TRUE;
	    }
         }
      } while (exit == FALSE);
      CloseWindow(window);
   }
   return(remove);
}
	/* Function table and functions for f1 to f10 */

VOID (*function_table[])() = {
   &back_window_to_front,	/* f1  */
   &front_window_to_back,	/* f2  */
   &activate_next_window,	/* f3  */
   &activate_previous_window,	/* f4  */
   &active_window_to_front,	/* f5  */
   &active_window_to_back,	/* f6  */
   &back_screen_to_front,	/* f7  */
   &front_screen_to_back,	/* f8  */
   &newcli,			/* f9  */
   &quit_program		/* f10 */
};

   VOID
back_window_to_front()		/* f1 */
{
   struct Window  *window = bottom_window(IntuitionBase->ActiveScreen);

   if (window) {
      while (window && (window->Flags & BACKDROP)) {
	 window = previous_window(window);   /* skip backdrop windows */
      }
      if (window) {
	 WindowToFront(window);
	 ActivateWindow(window);
      }
   }
}

   VOID
front_window_to_back()		/* f2 */
{
   struct Window  *window1 = top_window(IntuitionBase->ActiveScreen);
   struct Window  *window2 = next_window(window1);

   if (window1) {
      WindowToBack(window1);
      if (window2) {
	 ActivateWindow(window2);
      }
   }
}

   VOID
activate_next_window()		/* f3 */
{
   struct Window  *window = next_window(IntuitionBase->ActiveWindow);

   if (window) {
      ActivateWindow(window);
   }
}

   VOID
activate_previous_window()	/* f4 */
{
   struct Window  *window = previous_window(IntuitionBase->ActiveWindow);

   if (window == NULL) {
      window = bottom_window(IntuitionBase->ActiveScreen);
   }
   if (window) {
      ActivateWindow(window);
   }
}

   VOID
active_window_to_front()	/* f5 */
{
   struct Window  *window = IntuitionBase->ActiveWindow;

   if (window) {
      WindowToFront(window);
   }
}

   VOID
active_window_to_back()		/* f6 */
{
   struct Window  *window = IntuitionBase->ActiveWindow;

   if (window) {
      WindowToBack(window);
   }
}

   VOID
back_screen_to_front()		/* f7 */
{
   struct Screen  *screen = IntuitionBase->FirstScreen;
   struct Window  *window;

   if (screen) {
      while (screen->NextScreen) {
	 screen = screen->NextScreen;
      }
      ScreenToFront(screen);
      if (window = top_window(screen)) {
	 ActivateWindow(window);
      }
   }
}

   VOID
front_screen_to_back()		/* f8 */
{
   struct Screen  *screen = IntuitionBase->FirstScreen;
   struct Window  *window;

   if (screen) {
      ScreenToBack(screen);
      if (screen = IntuitionBase->FirstScreen) {
	 if (window = top_window(screen)) {
	    ActivateWindow(window);
	 }
      }
   }
}

   VOID
newcli()			/* f9 */
{
   action = ACTION_NEWCLI;
   Signal(main_task, SIGB_ACTION);   /* send action signal to main task */
}

   VOID
quit_program()			/* f10 */
{
   action = ACTION_REMOVE_REQUESTER;
   Signal(main_task, SIGB_ACTION);   /* send action signal to main task */
}
	/* Support routines for functions */

   struct Window  *
top_window(screen)
   struct Screen  *screen;
{
   struct Window  *window = NULL;
   struct Layer   *layer  = screen->LayerInfo.top_layer;

   while (layer && layer->Window == NULL) {
      layer = layer->back;
   }
   if (layer) {
      window = (struct Window *)layer->Window;
   }
   return(window);
}

   struct Window  *
bottom_window(screen)
   struct Screen  *screen;
{
   struct Window  *window = NULL;
   struct Layer   *layer  = screen->LayerInfo.top_layer;

   while (layer) {
      if (layer->Window) {
         window = (struct Window *)layer->Window;
      }
      layer = layer->back;
   }
   return(window);
}

   struct Window  *
next_window(window)
   struct Window  *window;
{
   struct Layer  *layer = window->WLayer;

   do {
      layer = layer->back;
   } while (layer && layer->Window == NULL);
   if (layer) {
      window = (struct Window *)layer->Window;
   } else {
      window = top_window(window->WScreen);
   }
   return(window);
}

   struct Window  *
previous_window(window)
   struct Window  *window;
{
   struct Layer  *layer = window->WLayer;

   do {
      layer = layer->front;
   } while (layer && layer->Window == NULL || layer->Window == window);
   if (layer) {
      window = (struct Window *)layer->Window;
   } else {
      window = NULL;
   }
   return(window);
}
