mirror of
https://github.com/reactos/reactos.git
synced 2024-12-25 16:50:57 +00:00
456be5d16b
svn path=/trunk/; revision=15091
681 lines
15 KiB
C
681 lines
15 KiB
C
/* --------- message.c ---------- */
|
|
|
|
#include "dflat32/dflat.h"
|
|
#include "dflat32/system.h"
|
|
|
|
static int handshaking = 0;
|
|
|
|
BOOL AllocTesting = FALSE;
|
|
jmp_buf AllocError;
|
|
BOOL AltDown = FALSE;
|
|
|
|
/* ---------- event queue ---------- */
|
|
static struct events
|
|
{
|
|
DFMESSAGE event;
|
|
int mx;
|
|
int my;
|
|
} EventQueue[MAXMESSAGES];
|
|
|
|
/* ---------- message queue --------- */
|
|
static struct msgs
|
|
{
|
|
DFWINDOW wnd;
|
|
DFMESSAGE msg;
|
|
PARAM p1;
|
|
PARAM p2;
|
|
} MsgQueue[MAXMESSAGES];
|
|
|
|
static int EventQueueOnCtr;
|
|
static int EventQueueOffCtr;
|
|
static int EventQueueCtr;
|
|
|
|
static int MsgQueueOnCtr;
|
|
static int MsgQueueOffCtr;
|
|
static int MsgQueueCtr;
|
|
|
|
|
|
DFWINDOW CaptureMouse;
|
|
DFWINDOW CaptureKeyboard;
|
|
static BOOL NoChildCaptureMouse;
|
|
static BOOL NoChildCaptureKeyboard;
|
|
|
|
static int doubletimer = -1;
|
|
static int delaytimer = -1;
|
|
static int clocktimer = -1;
|
|
|
|
static DFWINDOW Cwnd;
|
|
|
|
static char ermsg[] = "Error accessing drive x";
|
|
|
|
|
|
static void StopMsg(void)
|
|
{
|
|
ClearClipboard();
|
|
ClearDialogBoxes();
|
|
restorecursor();
|
|
unhidecursor();
|
|
}
|
|
|
|
SHORT DfGetScreenHeight (void)
|
|
{
|
|
return sScreenHeight;
|
|
}
|
|
|
|
SHORT DfGetScreenWidth (void)
|
|
{
|
|
return sScreenWidth;
|
|
}
|
|
|
|
/* ------------ initialize the message system --------- */
|
|
BOOL DfInitialize (VOID)
|
|
{
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
|
|
AllocTesting = TRUE;
|
|
if (setjmp(AllocError) != 0)
|
|
{
|
|
StopMsg();
|
|
return FALSE;
|
|
}
|
|
|
|
/* get input and output handles */
|
|
hInput = GetStdHandle (STD_INPUT_HANDLE);
|
|
hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
|
|
|
|
/* get screen size */
|
|
GetConsoleScreenBufferInfo (hOutput, &csbi);
|
|
sScreenHeight = (csbi.srWindow.Bottom - csbi.srWindow.Top) + 1;
|
|
sScreenWidth = (csbi.srWindow.Right - csbi.srWindow.Left) + 1;
|
|
|
|
/* enable mouse events */
|
|
SetConsoleMode (hInput, ENABLE_MOUSE_INPUT);
|
|
|
|
savecursor();
|
|
hidecursor();
|
|
|
|
CaptureMouse = NULL;
|
|
CaptureKeyboard = NULL;
|
|
NoChildCaptureMouse = FALSE;
|
|
NoChildCaptureKeyboard = FALSE;
|
|
MsgQueueOnCtr = 0;
|
|
MsgQueueOffCtr = 0;
|
|
MsgQueueCtr = 0;
|
|
EventQueueOnCtr = 0;
|
|
EventQueueOffCtr = 0;
|
|
EventQueueCtr = 0;
|
|
DfPostMessage (NULL, DFM_START, 0, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void DfTerminate (void)
|
|
{
|
|
|
|
}
|
|
|
|
/* ----- post an event and parameters to event queue ---- */
|
|
static void PostEvent(DFMESSAGE event, int p1, int p2)
|
|
{
|
|
if (EventQueueCtr != MAXMESSAGES) {
|
|
EventQueue[EventQueueOnCtr].event = event;
|
|
EventQueue[EventQueueOnCtr].mx = p1;
|
|
EventQueue[EventQueueOnCtr].my = p2;
|
|
if (++EventQueueOnCtr == MAXMESSAGES)
|
|
EventQueueOnCtr = 0;
|
|
EventQueueCtr++;
|
|
}
|
|
}
|
|
|
|
/* ------ collect mouse, clock, and keyboard events ----- */
|
|
static void collect_events(void)
|
|
{
|
|
static int OldShiftKeys = 0;
|
|
int sk = 0;
|
|
|
|
#ifdef TIMER_AVAILABLE
|
|
static BOOL flipflop = FALSE;
|
|
static char timestr[9];
|
|
struct tm *now;
|
|
int hr;
|
|
#endif
|
|
|
|
HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
|
|
INPUT_RECORD ir;
|
|
DWORD dwRead;
|
|
int c;
|
|
|
|
#ifdef TIMER_AVAILABLE
|
|
/* -------- test for a clock event (one/second) ------- */
|
|
if (timed_out(clocktimer))
|
|
{
|
|
/* ----- get the current time ----- */
|
|
time_t t = time(NULL);
|
|
now = localtime(&t);
|
|
hr = now->tm_hour > 12 ?
|
|
now->tm_hour - 12 :
|
|
now->tm_hour;
|
|
if (hr == 0)
|
|
hr = 12;
|
|
sprintf(timestr, "%2d:%02d", hr, now->tm_min);
|
|
strcpy(timestr+5, now->tm_hour > 11 ? "pm " : "am ");
|
|
/* ------- blink the : at one-second intervals ----- */
|
|
if (flipflop)
|
|
*(timestr+2) = ' ';
|
|
flipflop ^= TRUE;
|
|
/* -------- reset the timer -------- */
|
|
set_timer(clocktimer, 1);
|
|
/* -------- post the clock event -------- */
|
|
PostEvent(CLOCKTICK, (PARAM)timestr, 0);
|
|
}
|
|
#endif
|
|
|
|
// WaitForSingleObject (hInput, INFINITE);
|
|
ReadConsoleInput (hInput, &ir, 1, &dwRead);
|
|
|
|
if ((ir.EventType == KEY_EVENT) &&
|
|
(ir.Event.KeyEvent.bKeyDown == TRUE))
|
|
{
|
|
/* handle key down events */
|
|
|
|
/* handle shift state changes */
|
|
if (ir.Event.KeyEvent.dwControlKeyState &
|
|
(LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
|
|
{
|
|
sk |= ALTKEY;
|
|
}
|
|
if (ir.Event.KeyEvent.dwControlKeyState &
|
|
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
|
|
{
|
|
sk |= CTRLKEY;
|
|
}
|
|
if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
|
|
{
|
|
sk |= LEFTSHIFT + RIGHTSHIFT;
|
|
}
|
|
|
|
if (sk != OldShiftKeys)
|
|
{
|
|
OldShiftKeys = sk;
|
|
/* the shift status changed */
|
|
PostEvent(SHIFT_CHANGED, sk, 0);
|
|
#if 0
|
|
if (sk & ALTKEY)
|
|
AltDown = TRUE;
|
|
else
|
|
AltDown = FALSE;
|
|
#endif
|
|
}
|
|
|
|
if (ir.Event.KeyEvent.uChar.AsciiChar == 0)
|
|
{
|
|
switch (ir.Event.KeyEvent.wVirtualKeyCode)
|
|
{
|
|
case VK_F1:
|
|
c = F1;
|
|
break;
|
|
|
|
case VK_F4:
|
|
if (sk & ALTKEY)
|
|
c = ALT_F4;
|
|
else if (sk & CTRLKEY)
|
|
c = CTRL_F4;
|
|
else
|
|
c = F4;
|
|
|
|
case VK_F10:
|
|
c = F10;
|
|
break;
|
|
|
|
case VK_UP:
|
|
c = UP;
|
|
break;
|
|
|
|
case VK_DOWN:
|
|
c = DN;
|
|
break;
|
|
|
|
case VK_LEFT:
|
|
c = BS;
|
|
break;
|
|
|
|
case VK_RIGHT:
|
|
c = FWD;
|
|
break;
|
|
|
|
case VK_INSERT:
|
|
c = INS;
|
|
break;
|
|
|
|
case VK_DELETE:
|
|
c = DEL;
|
|
break;
|
|
|
|
case VK_HOME:
|
|
c = HOME;
|
|
break;
|
|
|
|
case VK_END:
|
|
c = END;
|
|
break;
|
|
|
|
case VK_PRIOR:
|
|
c = PGUP;
|
|
break;
|
|
|
|
case VK_NEXT:
|
|
c = PGDN;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* special handling of SHIFT+TAB */
|
|
if (ir.Event.KeyEvent.uChar.AsciiChar == VK_TAB &&
|
|
(ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED))
|
|
c = SHIFT_HT;
|
|
else
|
|
c = ir.Event.KeyEvent.uChar.AsciiChar;
|
|
}
|
|
|
|
PostEvent (KEYBOARD, c, sk);
|
|
}
|
|
else if (ir.EventType == MOUSE_EVENT)
|
|
{
|
|
/* handle mouse events */
|
|
if (ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
|
|
{
|
|
PostEvent (MOUSE_MOVED,
|
|
ir.Event.MouseEvent.dwMousePosition.X,
|
|
ir.Event.MouseEvent.dwMousePosition.Y);
|
|
}
|
|
else if (ir.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
|
|
{
|
|
if (ir.Event.MouseEvent.dwButtonState ==
|
|
FROM_LEFT_1ST_BUTTON_PRESSED)
|
|
{
|
|
PostEvent (DOUBLE_CLICK,
|
|
ir.Event.MouseEvent.dwMousePosition.X,
|
|
ir.Event.MouseEvent.dwMousePosition.Y);
|
|
}
|
|
}
|
|
else if (ir.Event.MouseEvent.dwEventFlags == 0)
|
|
{
|
|
/* single click */
|
|
if (ir.Event.MouseEvent.dwButtonState ==
|
|
FROM_LEFT_1ST_BUTTON_PRESSED)
|
|
{
|
|
PostEvent (LEFT_BUTTON,
|
|
ir.Event.MouseEvent.dwMousePosition.X,
|
|
ir.Event.MouseEvent.dwMousePosition.Y);
|
|
}
|
|
else if (ir.Event.MouseEvent.dwButtonState ==
|
|
RIGHTMOST_BUTTON_PRESSED)
|
|
{
|
|
PostEvent (RIGHT_BUTTON,
|
|
ir.Event.MouseEvent.dwMousePosition.X,
|
|
ir.Event.MouseEvent.dwMousePosition.Y);
|
|
}
|
|
else if (ir.Event.MouseEvent.dwButtonState == 0)
|
|
{
|
|
PostEvent (DFM_BUTTON_RELEASED,
|
|
ir.Event.MouseEvent.dwMousePosition.X,
|
|
ir.Event.MouseEvent.dwMousePosition.Y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ----- post a message and parameters to msg queue ---- */
|
|
void DfPostMessage(DFWINDOW wnd, DFMESSAGE msg, PARAM p1, PARAM p2)
|
|
{
|
|
if (msg == ENDDIALOG)
|
|
{
|
|
msg++;
|
|
--msg;
|
|
}
|
|
|
|
if (MsgQueueCtr != MAXMESSAGES)
|
|
{
|
|
MsgQueue[MsgQueueOnCtr].wnd = wnd;
|
|
MsgQueue[MsgQueueOnCtr].msg = msg;
|
|
MsgQueue[MsgQueueOnCtr].p1 = p1;
|
|
MsgQueue[MsgQueueOnCtr].p2 = p2;
|
|
if (++MsgQueueOnCtr == MAXMESSAGES)
|
|
MsgQueueOnCtr = 0;
|
|
MsgQueueCtr++;
|
|
}
|
|
}
|
|
|
|
/* --------- send a message to a window ----------- */
|
|
int DfSendMessage(DFWINDOW wnd, DFMESSAGE msg, PARAM p1, PARAM p2)
|
|
{
|
|
int rtn = TRUE, x, y;
|
|
|
|
#ifdef INCLUDE_LOGGING
|
|
LogMessages(wnd, msg, p1, p2);
|
|
#endif
|
|
if (wnd != NULL)
|
|
switch (msg) {
|
|
case PAINT:
|
|
case BORDER:
|
|
/* ------- don't send these messages unless the
|
|
window is visible -------- */
|
|
if (isVisible(wnd))
|
|
rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
|
|
break;
|
|
case RIGHT_BUTTON:
|
|
case LEFT_BUTTON:
|
|
case DOUBLE_CLICK:
|
|
case DFM_BUTTON_RELEASED:
|
|
/* --- don't send these messages unless the
|
|
window is visible or has captured the mouse -- */
|
|
if (isVisible(wnd) || wnd == CaptureMouse)
|
|
rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
|
|
break;
|
|
case KEYBOARD:
|
|
case SHIFT_CHANGED:
|
|
/* ------- don't send these messages unless the
|
|
window is visible or has captured the keyboard -- */
|
|
if (!(isVisible(wnd) || wnd == CaptureKeyboard))
|
|
break;
|
|
default:
|
|
rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
|
|
break;
|
|
}
|
|
/* ----- window processor returned true or the message was sent
|
|
to no window at all (NULL) ----- */
|
|
if (rtn != FALSE) {
|
|
/* --------- process messages that a window sends to the
|
|
system itself ---------- */
|
|
switch (msg) {
|
|
case DFM_STOP:
|
|
StopMsg();
|
|
break;
|
|
/* ------- clock messages --------- */
|
|
case CAPTURE_CLOCK:
|
|
Cwnd = wnd;
|
|
set_timer(clocktimer, 0);
|
|
break;
|
|
case RELEASE_CLOCK:
|
|
Cwnd = NULL;
|
|
disable_timer(clocktimer);
|
|
break;
|
|
/* -------- keyboard messages ------- */
|
|
case KEYBOARD_CURSOR:
|
|
if (wnd == NULL)
|
|
cursor((int)p1, (int)p2);
|
|
else if (wnd == inFocus)
|
|
cursor(GetClientLeft(wnd)+(int)p1,
|
|
GetClientTop(wnd)+(int)p2);
|
|
break;
|
|
case CAPTURE_KEYBOARD:
|
|
if (p2)
|
|
((DFWINDOW)p2)->PrevKeyboard=CaptureKeyboard;
|
|
else
|
|
wnd->PrevKeyboard = CaptureKeyboard;
|
|
CaptureKeyboard = wnd;
|
|
NoChildCaptureKeyboard = (int)p1;
|
|
break;
|
|
case RELEASE_KEYBOARD:
|
|
if (wnd != NULL)
|
|
{
|
|
if (CaptureKeyboard == wnd || (int)p1)
|
|
CaptureKeyboard = wnd->PrevKeyboard;
|
|
else
|
|
{
|
|
DFWINDOW twnd = CaptureKeyboard;
|
|
while (twnd != NULL)
|
|
{
|
|
if (twnd->PrevKeyboard == wnd)
|
|
{
|
|
twnd->PrevKeyboard = wnd->PrevKeyboard;
|
|
break;
|
|
}
|
|
twnd = twnd->PrevKeyboard;
|
|
}
|
|
if (twnd == NULL)
|
|
CaptureKeyboard = NULL;
|
|
}
|
|
wnd->PrevKeyboard = NULL;
|
|
}
|
|
else
|
|
CaptureKeyboard = NULL;
|
|
NoChildCaptureKeyboard = FALSE;
|
|
break;
|
|
case CURRENT_KEYBOARD_CURSOR:
|
|
curr_cursor(&x, &y);
|
|
*(int*)p1 = x;
|
|
*(int*)p2 = y;
|
|
break;
|
|
case SAVE_CURSOR:
|
|
savecursor();
|
|
break;
|
|
case RESTORE_CURSOR:
|
|
restorecursor();
|
|
break;
|
|
case HIDE_CURSOR:
|
|
normalcursor();
|
|
hidecursor();
|
|
break;
|
|
case SHOW_CURSOR:
|
|
if (p1)
|
|
set_cursor_size(100);
|
|
else
|
|
set_cursor_size(5);
|
|
unhidecursor();
|
|
break;
|
|
|
|
case CAPTURE_MOUSE:
|
|
if (p2)
|
|
((DFWINDOW)p2)->PrevMouse = CaptureMouse;
|
|
else
|
|
wnd->PrevMouse = CaptureMouse;
|
|
CaptureMouse = wnd;
|
|
NoChildCaptureMouse = (int)p1;
|
|
break;
|
|
|
|
case RELEASE_MOUSE:
|
|
if (wnd != NULL)
|
|
{
|
|
if (CaptureMouse == wnd || (int)p1)
|
|
CaptureMouse = wnd->PrevMouse;
|
|
else
|
|
{
|
|
DFWINDOW twnd = CaptureMouse;
|
|
while (twnd != NULL)
|
|
{
|
|
if (twnd->PrevMouse == wnd)
|
|
{
|
|
twnd->PrevMouse = wnd->PrevMouse;
|
|
break;
|
|
}
|
|
twnd = twnd->PrevMouse;
|
|
}
|
|
if (twnd == NULL)
|
|
CaptureMouse = NULL;
|
|
}
|
|
wnd->PrevMouse = NULL;
|
|
}
|
|
else
|
|
CaptureMouse = NULL;
|
|
NoChildCaptureMouse = FALSE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return rtn;
|
|
}
|
|
|
|
static DFRECT VisibleRect(DFWINDOW wnd)
|
|
{
|
|
DFRECT rc = WindowRect(wnd);
|
|
if (!TestAttribute(wnd, NOCLIP))
|
|
{
|
|
DFWINDOW pwnd = GetParent(wnd);
|
|
DFRECT prc;
|
|
prc = ClientRect(pwnd);
|
|
while (pwnd != NULL)
|
|
{
|
|
if (TestAttribute(pwnd, NOCLIP))
|
|
break;
|
|
rc = subRectangle(rc, prc);
|
|
if (!ValidRect(rc))
|
|
break;
|
|
if ((pwnd = GetParent(pwnd)) != NULL)
|
|
prc = ClientRect(pwnd);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* ----- find window that mouse coordinates are in --- */
|
|
static DFWINDOW inWindow(DFWINDOW wnd, int x, int y)
|
|
{
|
|
DFWINDOW Hit = NULL;
|
|
while (wnd != NULL) {
|
|
if (isVisible(wnd)) {
|
|
DFWINDOW wnd1;
|
|
DFRECT rc = VisibleRect(wnd);
|
|
if (InsideRect(x, y, rc))
|
|
Hit = wnd;
|
|
if ((wnd1 = inWindow(LastWindow(wnd), x, y)) != NULL)
|
|
Hit = wnd1;
|
|
if (Hit != NULL)
|
|
break;
|
|
}
|
|
wnd = PrevWindow(wnd);
|
|
}
|
|
return Hit;
|
|
}
|
|
|
|
static DFWINDOW MouseWindow(int x, int y)
|
|
{
|
|
/* get the window in which a mouse event occurred */
|
|
DFWINDOW Mwnd = inWindow(ApplicationWindow, x, y);
|
|
|
|
/* ---- process mouse captures ----- */
|
|
if (CaptureMouse != NULL)
|
|
{
|
|
if (NoChildCaptureMouse ||
|
|
Mwnd == NULL ||
|
|
!isAncestor(Mwnd, CaptureMouse))
|
|
Mwnd = CaptureMouse;
|
|
}
|
|
return Mwnd;
|
|
}
|
|
|
|
|
|
void handshake(void)
|
|
{
|
|
handshaking++;
|
|
DfDispatchMessage ();
|
|
--handshaking;
|
|
}
|
|
|
|
|
|
/* ---- dispatch messages to the message proc function ---- */
|
|
BOOL DfDispatchMessage (void)
|
|
{
|
|
DFWINDOW Mwnd, Kwnd;
|
|
|
|
/* -------- collect mouse and keyboard events ------- */
|
|
collect_events();
|
|
|
|
/* --------- dequeue and process events -------- */
|
|
while (EventQueueCtr > 0)
|
|
{
|
|
struct events ev;
|
|
|
|
ev = EventQueue[EventQueueOffCtr];
|
|
if (++EventQueueOffCtr == MAXMESSAGES)
|
|
EventQueueOffCtr = 0;
|
|
--EventQueueCtr;
|
|
|
|
/* get the window in which a keyboard event occurred */
|
|
Kwnd = inFocus;
|
|
|
|
/* process keyboard captures */
|
|
if (CaptureKeyboard != NULL)
|
|
{
|
|
if (Kwnd == NULL ||
|
|
NoChildCaptureKeyboard ||
|
|
!isAncestor(Kwnd, CaptureKeyboard))
|
|
Kwnd = CaptureKeyboard;
|
|
}
|
|
|
|
/* send mouse and keyboard messages to the
|
|
window that should get them */
|
|
switch (ev.event)
|
|
{
|
|
case SHIFT_CHANGED:
|
|
case KEYBOARD:
|
|
if (!handshaking)
|
|
DfSendMessage(Kwnd, ev.event, ev.mx, ev.my);
|
|
break;
|
|
|
|
case LEFT_BUTTON:
|
|
if (!handshaking)
|
|
{
|
|
Mwnd = MouseWindow(ev.mx, ev.my);
|
|
if (!CaptureMouse ||
|
|
(!NoChildCaptureMouse &&
|
|
isAncestor(Mwnd, CaptureMouse)))
|
|
{
|
|
if (Mwnd != inFocus)
|
|
DfSendMessage(Mwnd, SETFOCUS, TRUE, 0);
|
|
DfSendMessage(Mwnd, LEFT_BUTTON, ev.mx, ev.my);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DFM_BUTTON_RELEASED:
|
|
case DOUBLE_CLICK:
|
|
case RIGHT_BUTTON:
|
|
if (handshaking)
|
|
break;
|
|
|
|
case MOUSE_MOVED:
|
|
Mwnd = MouseWindow(ev.mx, ev.my);
|
|
DfSendMessage(Mwnd, ev.event, ev.mx, ev.my);
|
|
break;
|
|
|
|
case CLOCKTICK:
|
|
DfSendMessage(Cwnd, ev.event, ev.mx, ev.my);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ------ dequeue and process messages ----- */
|
|
while (MsgQueueCtr > 0)
|
|
{
|
|
struct msgs mq;
|
|
|
|
mq = MsgQueue[MsgQueueOffCtr];
|
|
|
|
if (++MsgQueueOffCtr == MAXMESSAGES)
|
|
MsgQueueOffCtr = 0;
|
|
--MsgQueueCtr;
|
|
|
|
DfSendMessage (mq.wnd, mq.msg, mq.p1, mq.p2);
|
|
if (mq.msg == ENDDIALOG)
|
|
return FALSE;
|
|
|
|
if (mq.msg == DFM_STOP)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* EOF */
|