1 /* aNetHack 0.0.1 amiwind.c $ANH-Date: 1432512794 2015/05/25 00:13:14 $ $ANH-Branch: master $:$ANH-Revision: 1.10 $ */
2 /* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */
3 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996 */
4 /* aNetHack may be freely redistributed. See license for details. */
6 #include "NH:sys/amiga/windefs.h"
7 #include "NH:sys/amiga/winext.h"
8 #include "NH:sys/amiga/winproto.h"
10 /* Have to undef CLOSE as display.h and intuition.h both use it */
13 #ifdef AMII_GRAPHICS /* too early in the file? too late? */
16 static struct Message
*FDECL(GetFMsg
, (struct MsgPort
*));
19 static int BufferGetchar(void);
20 static void ProcessMessage(register struct IntuiMessage
*message
);
22 #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
24 struct Library
*ConsoleDevice
;
26 #include "NH:sys/amiga/amimenu.c"
28 /* Now our own variables */
30 struct IntuitionBase
*IntuitionBase
;
31 struct Screen
*HackScreen
;
32 struct Window
*pr_WindowPtr
;
33 struct MsgPort
*HackPort
;
34 struct IOStdReq ConsoleIO
;
35 struct Menu
*MenuStrip
;
41 struct GfxBase
*GfxBase
;
42 struct Library
*DiskfontBase
;
46 static unsigned char KbdBuffer
[KBDBUFFER
];
47 unsigned char KbdBuffered
;
51 struct TextFont
*TextsFont
= NULL
;
52 struct TextFont
*HackFont
= NULL
;
53 struct TextFont
*RogueFont
= NULL
;
55 UBYTE FontName
[] = "aNetHack:hack.font";
56 /* # chars in "aNetHack:": */
57 #define SIZEOF_DISKNAME 8
61 struct TextAttr Hack80
= {
63 &FontName
[SIZEOF_DISKNAME
],
65 (UBYTE
*) "topaz.font",
67 8, FS_NORMAL
, FPF_DISKFONT
| FPF_DESIGNED
| FPF_ROMFONT
70 struct TextAttr TextsFont13
= { (UBYTE
*) "courier.font", 13, FS_NORMAL
,
71 FPF_DISKFONT
| FPF_DESIGNED
77 /* Avoid doing a ReplyMsg through a window that no longer exists. */
78 static enum { NoAction
, CloseOver
} delayed_key_action
= NoAction
;
81 * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
89 register struct Window
*win
;
90 register ULONG idcmpflags
;
92 if (!HackPort
) /* Sanity check */
93 return (struct Window
*) 0;
95 idcmpflags
= nw
->IDCMPFlags
;
97 if (!(win
= OpenWindow((void *) nw
))) {
98 nw
->IDCMPFlags
= idcmpflags
;
99 return (struct Window
*) 0;
102 nw
->IDCMPFlags
= idcmpflags
;
103 win
->UserPort
= HackPort
;
104 ModifyIDCMP(win
, idcmpflags
);
109 * Close a window that shared the HackPort IDCMP port.
112 void FDECL(CloseShWindow
, (struct Window
*));
117 register struct IntuiMessage
*msg
;
120 panic("HackPort NULL in CloseShWindow");
125 /* Flush all messages for all windows to avoid typeahead and other
126 * similar problems...
128 while (msg
= (struct IntuiMessage
*) GetMsg(win
->UserPort
))
129 ReplyMsg((struct Message
*) msg
);
131 win
->UserPort
= (struct MsgPort
*) 0;
132 ModifyIDCMP(win
, 0L);
142 if (KbdBuffered
> 0) {
145 /* Move the remaining characters */
146 if (KbdBuffered
< sizeof(KbdBuffer
))
147 memcpy(KbdBuffer
, KbdBuffer
+ 1, KbdBuffered
);
155 * This should remind you remotely of DeadKeyConvert, but we are cheating
156 * a bit. We want complete control over the numeric keypad, and no dead
157 * keys... (they are assumed to be on Alted keys).
159 * Also assumed is that the IntuiMessage is of type RAWKEY. For some
160 * reason, IECODE_UP_PREFIX events seem to be lost when they occur while
161 * our console window is inactive. This is particulary troublesome with
162 * qualifier keys... Is this because I never RawKeyConvert those events???
167 register struct IntuiMessage
*message
;
169 static struct InputEvent theEvent
;
170 static char numpad
[] = "bjnh.lyku";
171 static char ctrl_numpad
[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
172 static char shift_numpad
[] = "BJNH.LYKU";
174 unsigned char buffer
[10];
175 struct Window
*w
= message
->IDCMPWindow
;
177 register ULONG qualifier
;
178 char numeric_pad
, shift
, control
, alt
;
180 if (amii_wins
[WIN_MAP
])
181 w
= amii_wins
[WIN_MAP
]->win
;
182 qualifier
= message
->Qualifier
;
184 control
= (qualifier
& IEQUALIFIER_CONTROL
) != 0;
185 shift
= (qualifier
& (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) != 0;
186 alt
= (qualifier
& (IEQUALIFIER_LALT
| IEQUALIFIER_RALT
)) != 0;
188 /* Allow ALT to function as a META key ... */
189 /* But make it switchable - alt is needed for some non-US keymaps */
190 if (sysflags
.altmeta
)
191 qualifier
&= ~(IEQUALIFIER_LALT
| IEQUALIFIER_RALT
);
192 numeric_pad
= (qualifier
& IEQUALIFIER_NUMERICPAD
) != 0;
195 * Shortcut for HELP and arrow keys. I suppose this is allowed.
196 * The defines are in intuition/intuition.h, and the keys don't
197 * serve 'text' input, normally. Also, parsing their escape
198 * sequences is such a mess...
201 switch (message
->Code
) {
208 else if (WINVERS_AMIV
&& control
) {
211 CO
= (w
->Width
- w
->BorderLeft
- w
->BorderRight
) / mxsize
;
212 LI
= (w
->Height
- w
->BorderTop
- w
->BorderBottom
) / mysize
;
213 clipxmax
= CO
+ clipx
;
214 clipymax
= LI
+ clipy
;
215 if (CO
< COLNO
|| LI
< ROWNO
) {
217 amii_cliparound(u
.ux
, u
.uy
);
222 BufferQueueChar('R' - 64);
226 else if (WINVERS_AMIV
&& shift
) {
227 if (WIN_OVER
== WIN_ERR
) {
228 WIN_OVER
= amii_create_nhwindow(NHW_OVER
);
229 BufferQueueChar('R' - 64);
231 delayed_key_action
= CloseOver
;
255 theEvent
.ie_Class
= IECLASS_RAWKEY
;
256 theEvent
.ie_Code
= message
->Code
;
257 theEvent
.ie_Qualifier
= numeric_pad
? IEQUALIFIER_NUMERICPAD
: qualifier
;
258 theEvent
.ie_EventAddress
= (APTR
)(message
->IAddress
);
260 length
= RawKeyConvert(&theEvent
, (char *) buffer
, (long) sizeof(buffer
),
263 if (length
== 1) { /* Plain ASCII character */
266 * If iflags.num_pad is set, movement is by 4286.
267 * If not set, translate 4286 into hjkl.
268 * This way, the numeric pad can /always/ be used
269 * for moving, though best results are when it is off.
272 if (!iflags
.num_pad
&& numeric_pad
&& length
>= '1'
276 length
= ctrl_numpad
[length
];
278 length
= shift_numpad
[length
];
280 length
= numpad
[length
];
284 /* Kludge to allow altmeta on eg. scandinavian keymap (# ==
286 and prevent it from interfering with # command (M-#) */
287 if (length
== ('#' | 0x80))
289 if (alt
&& sysflags
.altmeta
)
292 } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
293 else if (length
> 1) {
296 if (length
== 3 && buffer
[0] == 155 && buffer
[2] == 126) {
303 mxsize
= mysize
= 16;
306 mxsize
= mysize
= 24;
309 mxsize
= mysize
= 32;
312 mxsize
= mysize
= 48;
323 CO
= (w
->Width
- w
->BorderLeft
- w
->BorderRight
) / mxsize
;
324 LI
= (w
->Height
- w
->BorderTop
- w
->BorderBottom
) / mysize
;
325 clipxmax
= CO
+ clipx
;
326 clipymax
= LI
+ clipy
;
327 if (CO
< COLNO
|| LI
< ROWNO
) {
328 amii_cliparound(u
.ux
, u
.uy
);
337 /*BufferQueueChar( 'R'-64 );*/
341 printf("Unrecognized key: %d ", (int) buffer
[0]);
342 for (i
= 1; i
< length
; ++i
)
343 printf("%d ", (int) buffer
[i
]);
350 * Process an incoming IntuiMessage.
351 * It would certainly look nicer if this could be done using a
352 * PA_SOFTINT message port, but we cannot call RawKeyConvert()
353 * during a software interrupt.
354 * Anyway, amikbhit()/kbhit() is called often enough, and usually gets
355 * ahead of input demands, when the user types ahead.
359 ProcessMessage(message
)
360 register struct IntuiMessage
*message
;
365 static int skip_mouse
= 0; /* need to ignore next mouse event on
366 * a window activation */
367 struct Window
*w
= message
->IDCMPWindow
;
369 switch (message
->Class
) {
371 if (alwaysinvent
&& WIN_INVEN
!= WIN_ERR
372 && w
== amii_wins
[WIN_INVEN
]->win
) {
373 cnt
= DoMenuScroll(WIN_INVEN
, 0, PICK_NONE
, &mip
);
374 } else if (scrollmsg
&& WIN_MESSAGE
!= WIN_ERR
375 && w
== amii_wins
[WIN_MESSAGE
]->win
) {
376 cnt
= DoMenuScroll(WIN_MESSAGE
, 0, PICK_NONE
, &mip
);
388 if (!amii_wins
[WIN_MAP
] || w
!= amii_wins
[WIN_MAP
]->win
)
391 if (message
->Code
== SELECTDOWN
) {
392 lastevent
.type
= WEMOUSE
;
393 lastevent
.un
.mouse
.x
= message
->MouseX
;
394 lastevent
.un
.mouse
.y
= message
->MouseY
;
395 /* With shift equals RUN */
396 lastevent
.un
.mouse
.qual
=
398 & (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) != 0;
404 struct MenuItem
*item
;
406 thismenu
= message
->Code
;
407 while (thismenu
!= MENUNULL
) {
408 item
= ItemAddress(MenuStrip
, (ULONG
) thismenu
);
409 if (KbdBuffered
< KBDBUFFER
)
410 BufferQueueChar((char) (GTMENUITEM_USERDATA(item
)));
411 thismenu
= item
->NextSelect
;
415 case REFRESHWINDOW
: {
416 if (scrollmsg
&& amii_wins
[WIN_MESSAGE
]
417 && w
== amii_wins
[WIN_MESSAGE
]->win
) {
418 cnt
= DoMenuScroll(WIN_MESSAGE
, 0, PICK_NONE
, &mip
);
423 if (WIN_INVEN
!= WIN_ERR
&& w
== amii_wins
[WIN_INVEN
]->win
) {
424 dismiss_nhwindow(WIN_INVEN
);
427 && (WIN_OVER
!= WIN_ERR
&& w
== amii_wins
[WIN_OVER
]->win
)) {
428 destroy_nhwindow(WIN_OVER
);
434 if (!(message
->Code
& IECODE_UP_PREFIX
)) {
435 /* May queue multiple characters
436 * but doesn't do that yet...
438 if ((c
= ConvertKey(message
)) > 0)
444 if (WIN_MESSAGE
!= WIN_ERR
&& w
== amii_wins
[WIN_MESSAGE
]->win
) {
445 cnt
= DoMenuScroll(WIN_MESSAGE
, 0, PICK_NONE
, &mip
);
446 } else if (WIN_INVEN
!= WIN_ERR
&& w
== amii_wins
[WIN_INVEN
]->win
) {
447 cnt
= DoMenuScroll(WIN_INVEN
, 0, PICK_NONE
, &mip
);
452 if (WIN_MESSAGE
!= WIN_ERR
&& w
== amii_wins
[WIN_MESSAGE
]->win
) {
454 /* Make sure that new size is honored for good. */
455 SetAPen(w
->RPort
, amii_msgBPen
);
456 SetBPen(w
->RPort
, amii_msgBPen
);
457 SetDrMd(w
->RPort
, JAM2
);
458 RectFill(w
->RPort
, w
->BorderLeft
, w
->BorderTop
,
459 w
->Width
- w
->BorderRight
- 1,
460 w
->Height
- w
->BorderBottom
- 1);
462 ReDisplayData(WIN_MESSAGE
);
463 } else if (WIN_INVEN
!= WIN_ERR
&& w
== amii_wins
[WIN_INVEN
]->win
) {
464 ReDisplayData(WIN_INVEN
);
465 } else if (WINVERS_AMIV
&& (WIN_OVER
!= WIN_ERR
466 && w
== amii_wins
[WIN_OVER
]->win
)) {
467 BufferQueueChar('R' - 64);
468 } else if (WIN_MAP
!= WIN_ERR
&& w
== amii_wins
[WIN_MAP
]->win
) {
470 CO
= (w
->Width
- w
->BorderLeft
- w
->BorderRight
) / mxsize
;
471 LI
= (w
->Height
- w
->BorderTop
- w
->BorderBottom
) / mysize
;
472 clipxmax
= CO
+ clipx
;
473 clipymax
= LI
+ clipy
;
474 if (CO
< COLNO
|| LI
< ROWNO
) {
475 amii_cliparound(u
.ux
, u
.uy
);
480 BufferQueueChar('R' - 64);
485 ReplyMsg((struct Message
*) message
);
487 switch (delayed_key_action
) {
489 amii_destroy_nhwindow(WIN_OVER
);
491 delayed_key_action
= NoAction
;
497 #endif /* AMII_GRAPHICS */
499 * Get all incoming messages and fill up the keyboard buffer,
500 * thus allowing Intuition to (maybe) free up the IntuiMessages.
501 * Return when no more messages left, or keyboard buffer half full.
502 * We need to do this since there is no one-to-one correspondence
503 * between characters and incoming messages.
506 #if defined(TTY_GRAPHICS) && !defined(AMII_GRAPHICS)
518 /* a kludge to defuse the mess in allmain.c */
519 /* I hope this is the right approach */
520 if (windowprocs
.win_init_nhwindows
== amii_procs
.win_init_nhwindows
)
535 register struct IntuiMessage
*message
;
536 while (KbdBuffered
< KBDBUFFER
/ 2) {
538 message
= (struct IntuiMessage
*) GetFMsg(HackPort
);
540 message
= (struct IntuiMessage
*) GetMsg(HackPort
);
543 ProcessMessage(message
);
544 if (lastevent
.type
!= WEUNK
&& lastevent
.type
!= WEKEY
)
549 return (lastevent
.type
== WEUNK
) ? KbdBuffered
: -1;
553 * Get a character from the keyboard buffer, waiting if not available.
554 * Ignore other kinds of events that happen in the mean time.
560 while ((lastevent
.type
= WEUNK
), amikbhit() <= 0) {
563 return BufferGetchar();
569 lastevent
.type
= WEUNK
;
570 while (amikbhit() == 0) {
575 lastevent
.type
= WEKEY
;
576 lastevent
.un
.key
= BufferGetchar();
578 return (lastevent
.type
);
582 * Clean up everything. But before we do, ask the user to hit return
583 * when there is something that s/he should read.
589 register struct IntuiMessage
*msg
;
591 /* Close things up */
597 if (ConsoleIO
.io_Device
)
598 CloseDevice((struct IORequest
*) &ConsoleIO
);
599 ConsoleIO
.io_Device
= 0;
601 if (ConsoleIO
.io_Message
.mn_ReplyPort
)
602 DeleteMsgPort(ConsoleIO
.io_Message
.mn_ReplyPort
);
603 ConsoleIO
.io_Message
.mn_ReplyPort
= 0;
605 /* Strip messages before deleting the port */
608 while (msg
= (struct IntuiMessage
*) GetMsg(HackPort
))
609 ReplyMsg((struct Message
*) msg
);
611 DeleteMsgPort(HackPort
);
616 /* Close the screen, under v37 or greater it is a pub screen and there may
617 * be visitors, so check close status and wait till everyone is gone.
620 #ifdef INTUI_NEW_LOOK
621 if (IntuitionBase
->LibNode
.lib_Version
>= 37) {
623 FreeMenus(MenuStrip
);
625 FreeVisualInfo(VisualInfo
);
626 while (CloseScreen(HackScreen
) == FALSE
) {
627 struct EasyStruct easy
= {
628 sizeof(struct EasyStruct
), 0, "Nethack Problem",
629 "Can't Close Screen, Close Visiting Windows", "Okay"
631 EasyRequest(NULL
, &easy
, NULL
, NULL
);
636 CloseScreen(HackScreen
);
648 CloseFont(TextsFont
);
653 CloseFont(RogueFont
);
658 CloseLibrary(DiskfontBase
);
664 CloseLibrary((struct Library
*) GadToolsBase
);
669 CloseLibrary((struct Library
*) LayersBase
);
674 CloseLibrary((struct Library
*) GfxBase
);
679 CloseLibrary((struct Library
*) IntuitionBase
);
680 IntuitionBase
= NULL
;
685 CloseLibrary((struct Library
*) DOSBase
);
690 ((struct Process
*) FindTask(NULL
))->pr_WindowPtr
= (APTR
) pr_WindowPtr
;
695 #endif /* AMII_GRAPHICS */
704 extern char orgdir
[];
708 if (Initialized
&& ConsoleDevice
709 && windowprocs
.win_init_nhwindows
== amii_procs
.win_init_nhwindows
) {
710 printf("\n\nAbort with alert code %08lx...\n", rc
);
714 printf("\n\nAbort with alert code %08lx...\n", rc
);
715 /* Alert(rc); this is too severe */
717 #ifdef INTUI_NEW_LOOK
718 if (IntuitionBase
->LibNode
.lib_Version
>= 37) {
719 struct EasyStruct es
= {
720 sizeof(struct EasyStruct
), 0, "aNetHack Panic Request",
721 "aNetHack is Aborting with code == 0x%08lx",
722 "Continue Abort|Return to Program|Clean up and exit",
724 fault
= EasyRequest(NULL
, &es
, NULL
, (long) rc
);
730 /* __emit(0x4afc); */ /* illegal instruction */
731 __emit(0x40fc); /* divide by */
732 __emit(0x0000); /* #0 */
733 /* NOTE: don't move amii_cleanup() above here - */
734 /* it is too likely to kill the system */
735 /* before it can get the SnapShot out, if */
736 /* there is something really wrong. */
740 if (windowprocs
.win_init_nhwindows
== amii_procs
.win_init_nhwindows
)
760 /* This routine adapted from AmigaMail IV-37 by Michael Sinz */
761 static struct Message
*
763 struct MsgPort
*port
;
765 struct IntuiMessage
*msg
, *succ
, *succ1
;
767 if (msg
= (struct IntuiMessage
*) GetMsg(port
)) {
768 if (!sysflags
.amiflush
)
769 return ((struct Message
*) msg
);
770 if (msg
->Class
== RAWKEY
) {
772 succ
= (struct IntuiMessage
*) (port
->mp_MsgList
.lh_Head
);
773 while (succ1
= (struct IntuiMessage
*) (succ
->ExecMessage
.mn_Node
775 if (succ
->Class
== RAWKEY
) {
776 Remove((struct Node
*) succ
);
777 ReplyMsg((struct Message
*) succ
);
784 return ((struct Message
*) msg
);
790 struct NewWindow
*win
;
792 struct NewWindow
*nwin
;
793 struct Gadget
*ngd
, *gd
, *pgd
= NULL
;
794 struct PropInfo
*pip
;
795 struct StringInfo
*sip
;
797 /* Copy the (Ext)NewWindow structure */
799 nwin
= (struct NewWindow
*) alloc(sizeof(struct NewWindow
));
802 /* Now do the gadget list */
804 nwin
->FirstGadget
= NULL
;
805 for (gd
= win
->FirstGadget
; gd
; gd
= gd
->NextGadget
) {
806 ngd
= (struct Gadget
*) alloc(sizeof(struct Gadget
));
808 if (gd
->GadgetType
== STRGADGET
) {
809 sip
= (struct StringInfo
*) alloc(sizeof(struct StringInfo
));
810 *sip
= *((struct StringInfo
*) gd
->SpecialInfo
);
811 sip
->Buffer
= (UBYTE
*) alloc(sip
->MaxChars
);
813 ngd
->SpecialInfo
= (APTR
) sip
;
814 } else if (gd
->GadgetType
== PROPGADGET
) {
815 pip
= (struct PropInfo
*) alloc(sizeof(struct PropInfo
));
816 *pip
= *((struct PropInfo
*) gd
->SpecialInfo
);
817 ngd
->SpecialInfo
= (APTR
) pip
;
820 pgd
->NextGadget
= ngd
;
822 nwin
->FirstGadget
= ngd
;
824 ngd
->NextGadget
= NULL
;
825 ngd
->UserData
= (APTR
) 0x45f35c3d; // magic cookie for FreeNewWindow()
832 struct NewWindow
*win
;
834 register struct Gadget
*gd
, *pgd
;
835 register struct StringInfo
*sip
;
837 for (gd
= win
->FirstGadget
; gd
; gd
= pgd
) {
838 pgd
= gd
->NextGadget
;
839 if ((ULONG
) gd
->UserData
== 0x45f35c3d) {
840 if (gd
->GadgetType
== STRGADGET
) {
841 sip
= (struct StringInfo
*) gd
->SpecialInfo
;
844 } else if (gd
->GadgetType
== PROPGADGET
) {
845 free((struct PropInfo
*) gd
->SpecialInfo
);
869 amii_number_pad(state
)
873 #endif /* AMII_GRAPHICS */
889 VA_DECL(const char *, s
)