/*
 * msg2evt.c --
 *
 * Copyright (c) 1994 Software Research Associates, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  Software Research
 * Associates makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
 */

#include "xlibInt.h" 
#ifdef KANJI
#include <mbctype.h>
#endif /* KANJI */

int mbflag =0;

/*
 *----------------------------------------------------------------------
 *
 * msgGetState --
 *
 *	Get the state of the modifier keys on the keyboard and,
 *	if desired, the mouse.
 *	'flag' needs to be non-zero for the mouse state to be
 *	included in the current mouse/keyboard state.
 *
 * Results:
 *	A short with the bits set for which modifier keys/buttons
 *	are currently pressed.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
short int
msgGetState(int flag)
{
    int state = 0;

    if (GetKeyState(VK_SHIFT) & 0x8000) state |= ShiftMask;
    if (GetKeyState(VK_CAPITAL) & 0x0001) state |= LockMask; 
    if (GetKeyState(VK_CONTROL) & 0x8000) state |= ControlMask; 
    if (GetKeyState(VK_NUMLOCK) & 0x0001) state |= Mod1Mask; 
/*    if (GetKeyState(VK_MENU) & 0x8000) state |= Mod2Mask; */
    if (GetKeyState(VK_SCROLL) & 0x0001)  state |= Mod3Mask; 
    if (flag) return (short) state;

    if (GetKeyState(VK_LBUTTON) & 0x8000) state |= Button1Mask;
    if (GetKeyState(VK_MBUTTON) & 0x8000) state |= Button3Mask; 
    if (GetKeyState(VK_RBUTTON) & 0x8000) state |= 
	(GetKeyState(VK_MENU) & 0x8000)?Button3Mask:Button2Mask;
    return (short) state;
}

/*
 *----------------------------------------------------------------------
 *
 * msg3event --
 *
 *	This routine generates most X events.  It converts Windows
 *	messages received by GetMessage() into X events if possible.
 *
 *	The serial number is placed in the lParam field for 
 *	CONFIGURENOTIFY messages because we need very accurate events.
 *	Really, all events should get their serial number when they
 *	are posted as opposed to here, but most don't matter that much.
 *
 * Results:
 *	0 if the message was handled, 1 if it was not.
 *	
 * Side Effects:
 *	Fills in the applicable fields of the passed in event if
 *	the message is handled.
 *
 *----------------------------------------------------------------------
 */
int					
msg3event(Display *display, MSG *mPtr, XEvent *ePtr)
{
    POINT sPt;	
    DWORD dw;
    WINDOWPOS * pWndPos;
    HDC hdc;
    PAINTSTRUCT ps;
    HGLOBAL hXSWAttrs;
    XSetWindowAttributes *pXSWAttrs;
    HBRUSH hBrush;

    ePtr->xany.window = (Window) mPtr->hwnd;
    ePtr->xany.serial = display->request;
    ePtr->xany.send_event = False;
    ePtr->xany.display = display;
    switch(mPtr->message) {
    case SOCKETNOTIFY:
	ePtr->type = SocketNotify;
	ePtr->xsocket.socket = mPtr->wParam;
	ePtr->xsocket.message = mPtr->lParam;
	break;

    case INPUTNOTIFY :
	ePtr->type = InputNotify;
	ePtr->xinput.window = (Window) mPtr->wParam;
	ePtr->xinput.fileno = mPtr->lParam;
	break;
		
    case TIMERNOTIFY :
	KillTimer(GetPostWindow(), 1);
	ePtr->type = TimerNotify; 
	break;

    case ACTIVATEAPP:
    	ePtr->type = ActivateApp;
	break;
				 
    case CREATENOTIFY :
	ePtr->type = CreateNotify;
	ePtr->xcreatewindow.x = ((CREATESTRUCT *) mPtr->lParam)->x;
	ePtr->xcreatewindow.y = ((CREATESTRUCT *) mPtr->lParam)->y;
	ePtr->xcreatewindow.border_width = 1;
	ePtr->xcreatewindow.override_redirect = False;
	break;

    case DESTROYNOTIFY :
	ePtr->type = DestroyNotify;
	ePtr->xdestroywindow.event = ePtr->xdestroywindow.window = (Window) mPtr->wParam; 
	break;

    case WM_LBUTTONDOWN :
    case WM_MBUTTONDOWN :
    case WM_RBUTTONDOWN :
    case WM_LBUTTONDBLCLK:
    case WM_MBUTTONDBLCLK:
    case WM_RBUTTONDBLCLK:
	if (GetCapture() != NULL) {
	    ReleaseCapture();
	}
	SetCapture(mPtr->hwnd);
    case WM_NCLBUTTONDOWN:
    case WM_NCMBUTTONDOWN:
    case WM_NCRBUTTONDOWN:
    case WM_NCLBUTTONDBLCLK:
    case WM_NCMBUTTONDBLCLK:
    case WM_NCRBUTTONDBLCLK:
	ePtr->type = ButtonPress;
	ePtr->xbutton.state = msgGetState(1);
	goto common_buttonevent;

    case WM_LBUTTONUP :
    case WM_MBUTTONUP :
    case WM_RBUTTONUP :
    case WM_NCLBUTTONUP:
    case WM_NCMBUTTONUP:
    case WM_NCRBUTTONUP:
	ePtr->type = ButtonRelease;
	if (GetCapture() != NULL) {
	    ReleaseCapture();
	}
	ePtr->xbutton.state = msgGetState(1);
    common_buttonevent:
	/* Note: the wParam may not be set if this event was generated
	 * in topproc.c
	 */
	ePtr->xbutton.same_screen = True;
	ePtr->xbutton.time = mPtr->time;
	ePtr->xbutton.x = sPt.x = (int) ((short) LOWORD(mPtr->lParam));
	ePtr->xbutton.y = sPt.y = (int) ((short) HIWORD(mPtr->lParam));

	ClientToScreen(mPtr->hwnd, &sPt);
	ePtr->xbutton.x_root = sPt.x;
	ePtr->xbutton.y_root = sPt.y;
	switch (mPtr->message) {
	case WM_LBUTTONDOWN:
	case WM_NCLBUTTONDOWN:
	case WM_LBUTTONDBLCLK:
	case WM_NCLBUTTONDBLCLK:
	    ePtr->xbutton.button = Button1;
	    ePtr->xbutton.state &= ~Button1Mask;
	    break;
	case WM_LBUTTONUP :
	case WM_NCLBUTTONUP:
	    ePtr->xbutton.button = Button1;
	    ePtr->xbutton.state |= Button1Mask;
	    break;
	case WM_MBUTTONDOWN:
	case WM_MBUTTONDBLCLK:
	case WM_NCMBUTTONDBLCLK:
	case WM_NCMBUTTONDOWN:
	    ePtr->xbutton.button = Button2;
	    ePtr->xbutton.state &= ~Button2Mask;
	    break;

	case WM_MBUTTONUP :
	case WM_NCMBUTTONUP:
	    ePtr->xbutton.button = Button2;
	    ePtr->xbutton.state |= Button2Mask;
	    break;
	case WM_RBUTTONDOWN:
	case WM_RBUTTONDBLCLK:
	case WM_NCRBUTTONDOWN:
	case WM_NCRBUTTONDBLCLK:
	    ePtr->xbutton.button = 
	    (GetKeyState(VK_MENU) & 0x8000)?Button3:Button2; break;	
	    ePtr->xbutton.button = Button3;
	    ePtr->xbutton.state &= ~Button3Mask;
	    break;

	case WM_RBUTTONUP :
	case WM_NCRBUTTONUP:
	    ePtr->xbutton.button = 
	    (GetKeyState(VK_MENU) & 0x8000)?Button3:Button2; break;	
	    ePtr->xbutton.button = Button3;
	    ePtr->xbutton.state |= Button3Mask;
	    break;
	}

	ePtr->xbutton.state &= ~Mod1Mask;
	break;

    case WM_MOUSEMOVE :   			/* MotionNotify */
	ePtr->type = MotionNotify;
	ePtr->xmotion.window = ePtr->xmotion.subwindow = (Window) mPtr->hwnd;
	ePtr->xmotion.root = HWND_DESKTOP;	  
	ePtr->xmotion.time = mPtr->time;
	ePtr->xmotion.x = sPt.x = (int) ((short) LOWORD(mPtr->lParam));
	ePtr->xmotion.y = sPt.y = (int) ((short) HIWORD(mPtr->lParam));
	ClientToScreen(mPtr->hwnd, &sPt);
	ePtr->xmotion.x_root = sPt.x;
	ePtr->xmotion.y_root = sPt.y;
	ePtr->xmotion.state = msgGetState(0);
	break;
        
    case FOCUSIN :			/* FocusIn Event */
	ePtr->type = FocusIn;
	ePtr->xfocus.mode = (keyboardGrabbed) ? NotifyGrab : NotifyNormal; 
	ePtr->xfocus.window = (Window) mPtr->hwnd; break;

    case FOCUSOUT :			/* FocusOut Event */
	ePtr->type = FocusIn;
	ePtr->xfocus.mode = (keyboardGrabbed) ? NotifyGrab : NotifyNormal; 
	ePtr->xfocus.window = (Window) mPtr->hwnd; break;

    case EXPOSE :			/* Expose Event (WM_PAINT) */
	if (!IsIconic(mPtr->hwnd)) {
	    hXSWAttrs = (HGLOBAL) GetWindowLong(mPtr->hwnd, XSWA_OFFSET);
	    if (hXSWAttrs == NULL) {
		return 0;
	    }
	    pXSWAttrs = (XSetWindowAttributes *) GlobalLock(hXSWAttrs);
	    hBrush = CreateSolidBrush(pXSWAttrs->background_pixel);
	    GlobalUnlock(hXSWAttrs);
	    hdc = BeginPaint(mPtr->hwnd, &ps); 
	    FillRect(hdc, &ps.rcPaint, hBrush);
	    DeleteObject(hBrush);

	    ePtr->xexpose.type = Expose;
	    ePtr->xexpose.x = (int) ps.rcPaint.left;
	    ePtr->xexpose.y = (int) ps.rcPaint.top;
	    ePtr->xexpose.width = (int) (ps.rcPaint.right - ps.rcPaint.left); 
	    ePtr->xexpose.height = (int) (ps.rcPaint.bottom - ps.rcPaint.top);

	    /* Really should find the true expose count.  To do this, we
	     * could peek at the messages before they are dispatched.
	     * If the events are put at the front of the queue instead
	     * of at the end, the count can be incremented for each PAINT
	     * message that we get for the window.
	     */
	    ePtr->xexpose.count = 0;

	    EndPaint(mPtr->hwnd, &ps);
	} else {
	    return 0;
	}
	break;

    case WM_CHAR: 
#ifdef KANJI    
	if(mbflag == 0 && _ismbblead((unsigned short)mPtr->wParam)) {
    		ePtr->xany.flag = 0x1234;
		mbflag = 1;
	} else if(mbflag == 1 && _ismbbtrail((unsigned short)mPtr->wParam)) {
    		ePtr->xany.flag = 0x5678;
		mbflag = 0;
	} else {
		mbflag = 0;
    		ePtr->xany.flag = 0xABCD;
		
	}       
#else 	
	mbflag = 0;
	ePtr->xany.flag = 0xABCD;
#endif /* KANJI */

    case KEYPRESS :			/* KeyPress Event */
	ePtr->type = KeyPress;
	goto common_keyevent;

    case KEYRELEASE :				/* KeyRelease Event */
	ePtr->type = KeyRelease;
    common_keyevent:
	ePtr->xkey.window = ePtr->xkey.subwindow = (Window) mPtr->hwnd;		  
	ePtr->xkey.root = HWND_DESKTOP; 	
	ePtr->xkey.time = mPtr->time;
	dw = GetMessagePos();
	sPt.x = (int) ((short) LOWORD(dw));
	sPt.y = (int) ((short) HIWORD(dw));
	ePtr->xkey.x_root = sPt.x;
	ePtr->xkey.y_root = sPt.y;
	ScreenToClient(mPtr->hwnd, &sPt);
	ePtr->xkey.x = sPt.x;
	ePtr->xkey.y = sPt.y; 
	ePtr->xkey.keycode = mPtr->wParam;
	ePtr->xkey.state = msgGetState(0);
	break;

    case MAPNOTIFY:			/* MapNotify, UnmapNotify Event */
	ePtr->type = MapNotify;
	goto common_mapevent;

    case UNMAPNOTIFY:
	ePtr->type = UnmapNotify;
    common_mapevent:
	ePtr->xmap.event = ePtr->xmap.window = (Window) mPtr->hwnd;		
	ePtr->xmap.override_redirect= False;
	break;

    case CONFIGURENOTIFY : 		/* ConfigureNotify, CirculateNotify Event */
	pWndPos = (WINDOWPOS *) GlobalLock((HGLOBAL) mPtr->wParam);
	ePtr->type = ConfigureNotify;
	ePtr->xany.serial = mPtr->lParam;
	ePtr->xconfigure.event = ePtr->xconfigure.window = (Window) mPtr->hwnd; 
	ePtr->xconfigure.x = pWndPos->x;
	ePtr->xconfigure.y = pWndPos->y;
	ePtr->xconfigure.width = pWndPos->cx;
	ePtr->xconfigure.height = pWndPos->cy;
	ePtr->xconfigure.border_width = 1;	
	ePtr->xconfigure.above = (Window) pWndPos->hwndInsertAfter;
	ePtr->xconfigure.override_redirect = False;
	GlobalUnlock((HGLOBAL) mPtr->wParam);
	GlobalFree((HGLOBAL) mPtr->wParam);
	break;

    case SELECTIONCLEAR:
    	ePtr->type = SelectionClear;
	ePtr->xselectionclear.window = (Window) mPtr->hwnd;
	ePtr->xselectionclear.selection = 0;
	ePtr->xselectionclear.serial = NextRequest(display);
	break;

    case CLIENTMESSAGE:
    	ePtr->type = ClientMessage;
	ePtr->xany.window = (Window) mPtr->wParam;
	ePtr->xclient.message_type = XInternAtom(display, "WM_PROTOCOLS", False);
	ePtr->xclient.data.l[0] = XInternAtom(display, "WM_DELETE_WINDOW", False);
	break;

    case SYSCOLORNOTIFY:
	ePtr->type = SyscolorNotify;
	ePtr->xany.window = (Window) mPtr->wParam;
	break;

    default :
	return 0;
    }
    return 1;
}
