📄 eventlow.c
字号:
/*
COW : Character Oriented Windows
event.c - Main event handler
*/
#define COW
#include <cow.h>
#define EVENT
#include <uevent.h>
#include <vkey.h>
#include <umenu.h>
#include <uwindow.h>
#include <uscreen.h>
#include <kinput.h>
#include <kkeyboar.h>
#include <uutil.h>
#ifdef EXTRAS
#include <cowextra.h>
#endif
#ifdef KK_UNIT
BOOL FARPUBLIC KKFilter(PMSG);
#endif
#ifdef WINDOW_OVERLAP
#include "overlap.h"
#endif
#include "window.h"
#include "menu.h"
#include "util.h"
#ifdef DUAL
#include <os2.h>
extern WORD fProtectMode;
#else
#ifdef DOS5
#include <os2.h>
#endif
#endif
#include "event.h"
#include "_event.h"
/* ----------------------------------------------------------------------- */
#ifdef RECORD_PLAYBACK
/* Forward declarations */
BOOL FAR PASCAL PlayBackMsg(MSG *);
VOID FAR PASCAL RecordMsg(MSG *);
#endif
#ifdef PROFILE
int PASCAL crefCow = 0; /* reference count of Cow Public entries */
#endif
#ifdef DOS5
/* NOTE : semaphore is CLEARED when a message is ready !! */
PUBLIC DWORD PASCAL semaMessage = 0; /* RAM semaphore */
#else
#ifdef DUAL
PUBLIC DWORD PASCAL semaMessage = 0; /* RAM semaphore */
#endif
PUBLIC BOOL PASCAL fMessage = FALSE;
#endif
PRIVATE PWND PASCAL pwndRoot = NULL; /* root window */
MSG msgNull = {0, WM_NULL, 0, 0l, timeMsgMax}; /* a NULL message */
MSGQ msgqAppl = {0, &msgNull, &msgqAppl.rgmsg[0]};
MSGQ msgqKeyboard = {0, &msgNull, &msgqKeyboard.rgmsg[0]};
MSGQ msgqMouse = {0, &msgNull, &msgqMouse.rgmsg[0]};
PMSG pmsgLast = &msgNull;
/* last message queued used by keyboard and mouse handlers */
PMSG pmsgLastKeyboard = &msgNull; /* for TSR kludge */
/* window with the focus */
PWND pwndFocus = NULL;
/* window with the mouse capture */
PWND pwndCapture = NULL;
/* Filter of messages */
PRIVATE BOOL FARPRIVATE DummyFilter(PMSG); /* forward declaration */
PRIVATE PFFN_FILTER pfnFilter = DummyFilter;
#ifdef WINDOW_OVERLAP
PRIVATE PFFN_FILTER pfnOverlapFilter = OverlapFilter;
#endif /*WINDOW_OVERLAP*/
/* Mouse control */
WORD timeDoubleClick = timeDoubleClickDefault;
MSP mspPrev = { 0xff, 0xff, 0xff, 0xff }; /* position of last move */
/* for 1 level of UngetMessage */
BYTE fUseCache = FALSE;
MSG msgCache;
/* Menu Info : see note in MENU.H */
PRIVATE MNI mniCur = { imenuNil, iitemNil, NULL, FALSE, FALSE, FALSE };
/* ----------------------------------------------------------------------- */
/* forward */
STATIC BOOL FNextMsg(MSG *);
STATIC VOID DequeueTopMsg(MSGQ *);
STATIC PWND PwndLocate(PWND, AX, AY);
STATIC VOID CheckDoubleClick(MSG *);
/* ----------------------------------------------------------------------- */
PUBLIC BOOL FARPUBLIC
PeekMessage(pmsg)
/*
-- check to see if a message is ready
-- return TRUE if *pmsg filled with a message
-- return FALSE if no messages pending
-- always poll the keyboard
*/
PMSG pmsg;
{
StartPublic();
do
{
/* don't always poll the keyboard */
if (fPollKeyboard)
PollKeyboard();
ClearMessage();
fAbort = FALSE;
/* try to get a message from Cache or Queue */
if (fUseCache)
{
*pmsg = msgCache;
fUseCache = FALSE;
/* if cached message is keyboard, use the current
focus */
if (msgCache.message >= WM_KEYFIRST &&
msgCache.message <= WM_KEYLAST)
pmsg->pwnd = pwndFocus;
}
else
{
if (!FNextMsg(pmsg))
{
/* event's background process */
if (!FCheckAlarm(pmsg))
ReturnPublic(FALSE, BOOL);
}
#ifdef RECORD_PLAYBACK
else
RecordMsg(pmsg);
#endif
}
}
#ifndef WINDOW_OVERLAP
#ifdef KK_UNIT
while (KKFilter(pmsg) || (*pfnFilter)(pmsg));
#else // KK_UNIT
while ((*pfnFilter)(pmsg));
#endif // KK_UNIT
#else
while ((*pfnFilter)(pmsg) || (*pfnOverlapFilter)(pmsg));
#endif /*WINDOW_OVERLAP*/
ReturnPublic(TRUE, BOOL);
}
STATIC BOOL
FNextMsg(pmsgDest)
/*
-- Obtain the next message from the queue by looking at the three event queues
-- return FALSE if there are no messages
-- fill *pmsgDest with the message
*/
PMSG pmsgDest;
{
/* Get a message from each of the queues */
PMSG pmsgAppl, pmsgKeyboard, pmsgMouse;
retry:
/* If the menu is active, block application messages */
pmsgAppl = FMenuActive() ? &msgNull : msgqAppl.pmsgHead;
pmsgKeyboard = msgqKeyboard.pmsgHead;
pmsgMouse = msgqMouse.pmsgHead;
if (pmsgKeyboard->time < pmsgAppl->time)
{
if (pmsgMouse->time < pmsgKeyboard->time)
goto mouse_event;
/* keyboard earliest */
pmsgKeyboard->pwnd = pwndFocus;
*pmsgDest = *pmsgKeyboard;
DequeueTopMsg(&msgqKeyboard);
pmsgLastKeyboard = pmsgLast;
#ifdef DOS3
/* if TSR present, poll to get next message */
fPollKeyboard = TRUE;
#endif /*DOS3*/
/* if message is a shift state change, call UpdateShiftKk */
if (pmsgDest->message == WM_KEYSTATE)
{
static WORD ssOld = 0;
#ifdef KANJI
static WORD ssOldKj = 0;
#endif
UpdateShiftKk(pmsgDest->wParam, ssOld);
ssOld = pmsgDest->wParam;
#ifdef KANJI
UpdateShiftKj(LOWORD(pmsgDest->lParam), ssOldKj);
ssOldKj = LOWORD(pmsgDest->lParam);
#endif
goto retry; /* get another */
}
}
else if (pmsgMouse->time < pmsgAppl->time)
{
/* mouse earliest */
mouse_event:
*pmsgDest = *pmsgMouse;
DequeueTopMsg(&msgqMouse);
/* clean up mouse message */
FindMouseWnd(pmsgDest);
CheckDoubleClick(pmsgDest);
#ifdef DEBUG
/* RIGHT BUTTON USED AS DEVELOPMENT HOOK */
if (pmsgDest->message == WM_RBUTTONDOWN &&
FTrapMouseRbutton())
goto retry;
#endif /*DEBUG*/
}
else if (pmsgAppl->time != timeMsgMax)
{
/* application earliest */
*pmsgDest = *pmsgAppl;
DequeueTopMsg(&msgqAppl);
}
else
{
/* all 3 queues had null messages when we entered */
#ifdef RECORD_PLAYBACK
{
static BOOL fPlayback = FALSE;
if ((fPlayback = !fPlayback) && PlayBackMsg (pmsgDest))
{
if (pmsgDest->message >= WM_MOUSEFIRST &&
pmsgDest->message <= WM_MOUSELAST)
FindMouseWnd(pmsgDest);
else
pmsgDest->pwnd = pwndFocus;
return TRUE;
}
}
#endif
if (!FMenuActive())
return FALSE; /* no message available */
/* never return if inside menu */
*pmsgDest = msgNull;
}
return TRUE;
}
STATIC VOID
DequeueTopMsg(pmsgq)
/*
-- dequeue the top message of the specified queue
-- if pmsgLast == the message being dequeued, then set pmsgLast to &msgNull
-- the queue must be originally non-empty
-- if queue gets empty, stick &msgNull in head slot
*/
MSGQ *pmsgq;
{
DisableInterrupts();
AssertSz(pmsgq->cmsg > 0, "Dequeueing an empty queue");
if (pmsgLast == pmsgq->pmsgHead)
pmsgLast = &msgNull;
if (--pmsgq->cmsg == 0)
pmsgq->pmsgHead = &msgNull;
else if (++(pmsgq->pmsgHead) == &pmsgq->rgmsg[imsgMax])
pmsgq->pmsgHead = &pmsgq->rgmsg[0];
EnableInterrupts();
}
PUBLIC VOID FARPUBLIC
FlushAbort()
/*
-- Flush all keyboard messages up to the first ESCAPE
-- for TSR keyboard input there should be 1 escape key only
-- can be called from TSR with SS != DS
*/
{
REGISTER MSG *pmsg;
/* if a key in the cache, then flush it */
if (fUseCache && msgCache.message >= WM_KEYFIRST &&
msgCache.message <= WM_KEYLAST)
{
/* it was a keyboard message */
fUseCache = FALSE;
if (msgCache.message == WM_CHAR && msgCache.wParam == VK_ESCAPE)
return; /* already have an escape */
}
while ((pmsg = msgqKeyboard.pmsgHead) != &msgNull)
{
BOOL fDone;
fDone = pmsg->wParam == LOBYTE(VK_ESCAPE);
DequeueTopMsg(&msgqKeyboard);
if (fDone)
break; /* quit after first ESCAPE */
}
}
#ifdef KANJI
VOID FAR PASCAL /* called by kanji keyboard driver */
KeyboardMessage(sc, vw, wParamKey, kk, fKeyUp)
#else // !KANJI
VOID FAR PASCAL /* called by keyboard driver */
KeyboardMessage(vw, wParamKey, kk, fKeyUp)
#endif // KANJI
/*
-- called by PollKeyboard for polled input
-- normally generate only WM_CHAR Messages
-- two special cases for WM_KEYUP :
VK_SPACE (needed for buttons)
VK_MENU (needed for menus)
-- all events at this level set Message
*/
#ifdef KANJI
BYTE sc; /* Scan code for KANJI KK-unit */
#endif // KANJI
BYTE vw; /* Windows virtual key */
WORD wParamKey; /* wParam for WM_KEY */
REGISTER WORD kk; /* KK shift states */
BOOL fKeyUp; /* TRUE => WM_KEYUP, FALSE => WM_CHAR */
{
WORD message;
WORD vk; /* the virtual key only */
#ifdef KANJI
WORD kj; /* KJ shift states */
kj = kk & KJ_KK;
Assert((kj & KJ_COUNT) == 0);
kk &= ~KK_VK;
#endif
Assert(vw <= 0xff);
vk = VkOfVw(vw); /* change virtual key */
#ifndef KANJI
Assert((kk & KK_VK) == 0);
#endif
if (!fKeyUp)
{
/* key depressed */
message = WM_CHAR;
if (vk == VK_ESCAPE)
{
/* ABORT case */
fAbort = TRUE;
}
else if (pmsgLast->message == WM_CHAR &&
#ifdef KANJI
(pmsgLast->lParam & KJ_COUNT) < KJ_COUNT &&
#endif
pmsgLast->wParam == wParamKey &&
kk == HIWORD(pmsgLast->lParam) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -