/*
Copyright 1990-2003 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/

#include <stdio.h>
#include <locale.h>
#include <X11/Xmd.h>
#include <Xm/Xm.h>
#include <X11/cursorfont.h>
#include <Xm/DrawingA.h>
#include <Xm/Label.h>
#include <Xm/MwmUtil.h>

#include "KeyboardAux.h"
#include "CmnFunction.h"
#include "SunIM.h"
#include "hzinput.h"

#define FONTNAME_CTRLKEY 	"8x13bold";
#define FONTNAME_NORMALKEY	"-*-*-medium-r-normal--14-*-*-*-*-*-*-*";

KeyboardAuxData gVKData;
Display		*gDisplay;
int		gLocaleID;

extern AuxCommonData 	gCommonData;

extern int 		gKeyboardNum;
extern VirtualKeyboard 	*gVKB[], *gIMEVKB[];

void KeyboardAux_InitAttributes();
void KeyboardAux_InitDimensions();
void KeyboardAux_InitObjects();
void KeyboardAux_FreeObjects();
void KeyboardAux_DestroyProc(Widget, XtPointer, XtPointer);
void KeyboardAux_LeaveWindowProc(Widget, XtPointer,XEvent*, Boolean*);
void KeyboardAux_ExposeProc(Widget, XtPointer, XEvent*, Boolean*);
void KeyboardAux_ButtonPressProc(Widget, XtPointer,XEvent*, Boolean*);
void KeyboardAux_ButtonReleaseProc(Widget, XtPointer,XEvent*, Boolean*);
void KeyboardAux_PointerMotionProc(Widget, XtPointer,XEvent*, Boolean*);
void KeyboardAux_KeyReleaseProc(Widget, XtPointer,XEvent*, Boolean*);
void KeyboardAux_DrawKeyButton(int nKeyButtonID, int bPushed);
void KeyboardAux_DrawAllButtons();
void KeyboardAux_UpdateStatus();
void KeyboardAux_Set_KeyEvent(int *nKeyCode, int *nKeyChar, int *nKeyStatus, int nKeyButtonID);
void KeyboardAux_Press_Key(int nKeyButtonID);

int main(int argc, char **argv)
{
	XtAppContext    app;
	Widget shell, drawarea, label;

	int nArg;
	Arg arrArg[16];
	
	char *locale_name = NULL;

	XtSetLanguageProc((XtAppContext)0, (XtLanguageProc)0, (XtPointer)0);

	nArg = 0;
	XtSetArg(arrArg[nArg], XmNx, 10); nArg++;
	XtSetArg(arrArg[nArg], XmNy, 600); nArg++;
	XtSetArg(arrArg[nArg], XmNmwmDecorations, 0); nArg++;
	XtSetArg(arrArg[nArg], XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_RESIZE); nArg++;
	XtSetArg(arrArg[nArg], XmNinput, FALSE); nArg++;
	XtSetArg(arrArg[nArg], XmNdefaultPosition, FALSE); nArg++;
	shell = XtAppInitialize(&app, "KeyboardAux", NULL, 0, &argc, argv, NULL, arrArg, nArg);

	locale_name = setlocale(LC_CTYPE, NULL);
	if (locale_name == NULL) return;
	locale_name = (char *) strdup(locale_name);
	gLocaleID = get_encodeid_from_locale(locale_name);
	free(locale_name);

	XtAddCallback(shell, XmNdestroyCallback, KeyboardAux_DestroyProc, NULL);
	gVKData.wdtShell = shell;
	gDisplay = XtDisplay(shell);

	nArg = 0;
	drawarea = XtCreateManagedWidget("PaletteArea", xmDrawingAreaWidgetClass, shell, arrArg, nArg);
	gVKData.wdtVKArea = drawarea;

	XtAddEventHandler(drawarea, ExposureMask, FALSE, KeyboardAux_ExposeProc, NULL);
	XtAddEventHandler(drawarea, ButtonPressMask, FALSE, KeyboardAux_ButtonPressProc, NULL);
	XtAddEventHandler(drawarea, ButtonReleaseMask, FALSE, KeyboardAux_ButtonReleaseProc, NULL);
	XtAddEventHandler(drawarea, PointerMotionMask, FALSE, KeyboardAux_PointerMotionProc, NULL);
	XtAddEventHandler(drawarea, KeyReleaseMask, FALSE, KeyboardAux_KeyReleaseProc, NULL);

	XtSetMappedWhenManaged(shell, FALSE);
	XtRealizeWidget(shell);

	/* Make dtsession do not save the geometry information */
	XSetCommand(XtDisplay(shell), XtWindow(shell), NULL, 0);

	/* Initialize the Keyboard informations */
	KeyboardAux_InitDimensions();
	KeyboardAux_InitObjects();

	/* Register aux class */
	if (xaux_ext_register_classes(shell) == -1) {
		return(-1);
	}

	XtAppMainLoop(app);
}

void KeyboardAux_InitDimensions()
{
	XRectangle *KeyButtonFrame;
	int nXPos, nYPos, nXMargin, nYMargin;
	int nHeight, nWidth, nButtonHeight, nButtonWidth;
	int nFrameHeight, nFrameWidth;
	int nYDelta = 1;
	int i, j;

	KeyButtonFrame = gVKData.KeyButtonFrame;

	nButtonHeight = 32;
	nButtonWidth  = 26;
	nXMargin = 3;
	nYMargin = 3;

	/* layout for the first line */
	nXPos = nXMargin;
	nYPos = nYMargin;

	for (i=VK_quotedbl; i<=VK_equal; i++) {
		nWidth = nButtonWidth;
		KeyButtonFrame[i].x = nXPos;
		KeyButtonFrame[i].y = nYPos;
		KeyButtonFrame[i].width = nWidth;
		KeyButtonFrame[i].height = nButtonHeight;
		nXPos += nWidth;
	} 

	i = VK_BackSpace + MAX_BASEKEY_NUM;
	nWidth = nButtonWidth * 2;
	KeyButtonFrame[i].x = nXPos;
	KeyButtonFrame[i].y = nYPos;
	KeyButtonFrame[i].width = nWidth;
	KeyButtonFrame[i].height = nButtonHeight;

	/* layout for the second line */
	nXPos = nXMargin;
	nYPos += nButtonHeight + nYDelta;

	i = VK_Tab + MAX_BASEKEY_NUM;
	nWidth = nButtonWidth * 3 / 2;
	KeyButtonFrame[i].x = nXPos;
	KeyButtonFrame[i].y = nYPos;
	KeyButtonFrame[i].width = nWidth;
	KeyButtonFrame[i].height = nButtonHeight;
	nXPos += nWidth;

	for (i=VK_q; i<=VK_backslash; i++) {
		nWidth = nButtonWidth;
		if (i == VK_backslash) nWidth = nButtonWidth * 3 / 2;

		KeyButtonFrame[i].x = nXPos;
		KeyButtonFrame[i].y = nYPos;
		KeyButtonFrame[i].width = nWidth;
		KeyButtonFrame[i].height = nButtonHeight;
		nXPos += nWidth;
	} 

	/* layout for the third line */
	nXPos = nXMargin;
	nYPos += nButtonHeight + nYDelta;

	i = VK_Caps_Lock + MAX_BASEKEY_NUM;
	nWidth = nButtonWidth * 2;
	KeyButtonFrame[i].x = nXPos;
	KeyButtonFrame[i].y = nYPos;
	KeyButtonFrame[i].width = nWidth;
	KeyButtonFrame[i].height = nButtonHeight;
	nXPos += nWidth;

	for (i=VK_a; i<=VK_apostrophe; i++) {
		nWidth = nButtonWidth;
		KeyButtonFrame[i].x = nXPos;
		KeyButtonFrame[i].y = nYPos;
		KeyButtonFrame[i].width = nWidth;
		KeyButtonFrame[i].height = nButtonHeight;
		nXPos += nWidth;
	} 

	i = VK_Enter + MAX_BASEKEY_NUM;
	nWidth = nButtonWidth * 2;
	KeyButtonFrame[i].x = nXPos;
	KeyButtonFrame[i].y = nYPos;
	KeyButtonFrame[i].width = nWidth;
	KeyButtonFrame[i].height = nButtonHeight;
	nXPos += nWidth;

	/* layout for the fourth line */
	nXPos = nXMargin;
	nYPos += nButtonHeight + nYDelta;

	i = VK_Shift_L + MAX_BASEKEY_NUM;
	nWidth = nButtonWidth * 5 / 2;
	KeyButtonFrame[i].x = nXPos;
	KeyButtonFrame[i].y = nYPos;
	KeyButtonFrame[i].width = nWidth;
	KeyButtonFrame[i].height = nButtonHeight;
	nXPos += nWidth;

	for (i=VK_z; i<=VK_slash; i++) {
		nWidth = nButtonWidth;
		KeyButtonFrame[i].x = nXPos;
		KeyButtonFrame[i].y = nYPos;
		KeyButtonFrame[i].width = nWidth;
		KeyButtonFrame[i].height = nButtonHeight;
		nXPos += nWidth;
	} 

	/* layout for the fifth line */
	nXPos = nXMargin;
	nYPos += nButtonHeight + nYDelta;

	for (i=VK_Control_L; i<=VK_escape; i++) {
		nWidth = 2 * nButtonWidth;
		if (i == VK_space)  nWidth = 7 * nButtonWidth;
		if (i == VK_escape) nXPos += 2 * nButtonWidth;
		j = i + MAX_BASEKEY_NUM;
		KeyButtonFrame[j].x = nXPos;
		KeyButtonFrame[j].y = nYPos;
		KeyButtonFrame[j].width = nWidth;
		KeyButtonFrame[j].height = nButtonHeight;
		nXPos += nWidth;
	} 

	/* Calculate the frame dimension of the Virtual keyboard */
	nWidth = 15 * nButtonWidth + 2 * nXMargin;
	nHeight = 5 * nButtonHeight + 2 * nYMargin + 4 * nYDelta;

	SetRectangle(&gVKData.rcKeyboardFrame, 0, 0, nWidth, nHeight);
	XtVaSetValues(gVKData.wdtShell, XmNwidth, nWidth, XmNheight, nHeight, NULL);
	XtVaSetValues(gVKData.wdtVKArea, XmNwidth, nWidth, XmNheight, nHeight, NULL);
}

/* Initialize some variables: Font */
void KeyboardAux_InitObjects()
{
	Display* pDisplay = XtDisplay(gVKData.wdtShell);
	char **missing_list, *def_string;
	char *fontname_ctrl, *fontname_normal;
	int  missing_count, i;

	XmFontList          fontlist;
	XmFontListEntry     entry1;

	fontname_ctrl = FONTNAME_CTRLKEY;
	fontname_normal = FONTNAME_NORMALKEY;

	/* Create Normal Key Font/GC Information */
	gVKData.fontset_normal = XCreateFontSet(pDisplay, fontname_normal,
				&missing_list, &missing_count, &def_string);

	if (missing_count > 0) {
/*
                printf("The following charsets are missing:\n");
                for (i=0; i<missing_count; i++)
                    printf("%s \n", missing_list[i]);
*/
                XFreeStringList(missing_list);
	}

	if (gVKData.fontset_normal == NULL) {
		DEBUG_printf("Error:  normal key's fontset is NULL\n");
	}

	entry1 = XmFontListEntryLoad (pDisplay, fontname_ctrl, XmFONT_IS_FONT, "TAG1");
	fontlist = XmFontListAppendEntry (NULL, entry1);
	gVKData.fontlist_ctrl = fontlist;

	Keyboards_Init();
	CommonData_Init(pDisplay);

	gVKData.x = 0;
	gVKData.y = 0;
	gVKData.nKeyboardID = -1;
	gVKData.nEngineID = 0;
	gVKData.nCtrlKey_Status = 0;
	gVKData.nShiftKey_Status = 0;
	gVKData.nAltKey_Status = 0;
	gVKData.nCapsLockKey_Status = 0;
}

void KeyboardAux_FreeObjects()
{
	Display* pDisplay = XtDisplay(gVKData.wdtShell);

	XFreeFontSet(pDisplay, gVKData.fontset_normal);
	XmFontListFree(gVKData.fontlist_ctrl);
	
	CommonData_Free();
	Keyboards_Done();
}

void KeyboardAux_DestroyProc(Widget widget, XtPointer pClientData, XtPointer pCallData)
{
	KeyboardAux_FreeObjects();
}

void KeyboardAux_ExposeProc(Widget widget, XtPointer pClientData, XEvent *pEvent, Boolean *pbFlag)
{
	KeyboardAux_UpdateStatus();
}

void KeyboardAux_ButtonPressProc(Widget widget, XtPointer pClientData,
				XEvent* pEvent, Boolean* pbFlag)
{
	Display* pDisplay = XtDisplay(widget);
	XRectangle *KeyButtonFrame = gVKData.KeyButtonFrame;
	XPoint ptButton;
	int nPressedButtonID;

	SetPoint(&ptButton, pEvent->xbutton.x, pEvent->xbutton.y);
	
	if (pEvent->xbutton.button == 1) {
		if (pEvent->xbutton.send_event) {
		} else {
			XGrabPointer(pDisplay, XtWindow(gVKData.wdtVKArea), FALSE,
				ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
				GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
			
			nPressedButtonID = KeyboardAux_GetButtonIDByPoint(&ptButton);
			gVKData.nPressedButtonID = nPressedButtonID;
			if (nPressedButtonID != VK_movearea) {
				KeyboardAux_DrawKeyButton(nPressedButtonID, TRUE);
			} else {
				SetMovingBoxFrame(pEvent, &gVKData.rcKeyboardFrame);
			}
		}
	}
}

void KeyboardAux_ButtonReleaseProc(Widget widget, XtPointer pClientData,
				XEvent* pEvent, Boolean* pbFlag)
{
	XRectangle *KeyButtonFrame = gVKData.KeyButtonFrame;
	Display* pDisplay = XtDisplay(widget);
	XPoint ptButton;
	int nButtonID, nPressedButtonID;
	Dimension nXPos, nYPos;
	
	SetPoint(&ptButton, pEvent->xbutton.x, pEvent->xbutton.y);

	if (pEvent->xbutton.button == 1) {
		XUngrabPointer(pDisplay, CurrentTime);
		nPressedButtonID = gVKData.nPressedButtonID;
		if (nPressedButtonID == VK_movearea) {
			MoveWidgetToPoint(gVKData.wdtShell, pEvent, &gVKData.rcKeyboardFrame);

			/* notify LE that the Palette has change position. */
			XtVaGetValues(gVKData.wdtShell, XmNx, &nXPos, XmNy, &nYPos, NULL);

			DEBUG_printf("KeyboardAux: After move: nXPos:%d, nYPos:%d\n", nXPos, nYPos);
			gVKData.x = nXPos;
			gVKData.y = nYPos;

			KeyboardAux_Change_LE_Position_Request(nXPos, nYPos);

		} else {
			KeyboardAux_DrawKeyButton(nPressedButtonID, FALSE);
			if (PointInRectangle(&(KeyButtonFrame[nPressedButtonID]), &ptButton)) {
				KeyboardAux_Press_Key(nPressedButtonID);
			}
		}
	}
}

void KeyboardAux_PointerMotionProc(Widget widget, XtPointer pClientData,
                                 XEvent* pEvent, Boolean* pbFlag)
{
	Display* pDisplay = XtDisplay(gVKData.wdtShell);
	Window window = XtWindow(gVKData.wdtVKArea);
	XRectangle *KeyButtonFrame = gVKData.KeyButtonFrame;
	XPoint ptButton;
	int nButtonID, nPressedButtonID;
	int nCursor;
	
	SetPoint(&ptButton, pEvent->xbutton.x, pEvent->xbutton.y);

	if (Button1MotionMask & pEvent->xmotion.state) {
		/* if in Drag mode */
		nPressedButtonID = gVKData.nPressedButtonID;
		if (nPressedButtonID == VK_movearea)
			DrawMovingBoxFrameAtPoint(pEvent, &gVKData.rcKeyboardFrame);
	} else if (!(pEvent->xmotion.state & BUTTON_ALL_STATE)) {
		/* if in normal mode, no drag */
		nButtonID = KeyboardAux_GetButtonIDByPoint(&ptButton);
		nCursor = CURSOR_NONE;
		if (nButtonID == VK_movearea)
			nCursor = CURSOR_MOVE;
		SetCursorShape(pDisplay, window, nCursor);
	}	
}

void KeyboardAux_KeyReleaseProc(Widget widget, XtPointer pClientData,
				XEvent* pEvent, Boolean* pbFlag)
{
	int keycode, keychar, keystate;

	switch (pEvent->type) {
		case KeyRelease:
			KeyEventToVirtualKey((XKeyEvent *) pEvent, &keycode, &keychar, &keystate);
			KeyboardAux_Commit_Key_Request(keycode, keychar, keystate);
			break;
		default:
			break;
	}
	return;
}

int  KeyboardAux_GetButtonIDByPoint(XPoint *ptButton)
{
	XRectangle *KeyButtonFrame = gVKData.KeyButtonFrame;
	int i;

	for (i = 0; i < MAX_VK_NUM; i++)
		if (PointInRectangle(&(KeyButtonFrame[i]), ptButton)) 
			return(i);

	return(VK_movearea);
}

void KeyboardAux_DrawKeyboardFrame()
{
	Display* pDisplay = XtDisplay(gVKData.wdtShell);
	int nScreenNo = DefaultScreen(pDisplay);
	GC defGC = DefaultGC(pDisplay, nScreenNo);
	Window window = XtWindow(gVKData.wdtVKArea);
	XRectangle rcFrame;
	Pixel backPixel, forePixel;
	int nXPos, nYPos, nWidth, nHeight;
	
	XClearWindow(pDisplay, window);

	nXPos = gVKData.rcKeyboardFrame.x;
	nYPos = gVKData.rcKeyboardFrame.y;
	nWidth = gVKData.rcKeyboardFrame.width;
	nHeight = gVKData.rcKeyboardFrame.height;

	XtVaGetValues(gVKData.wdtVKArea, XmNbackground, &backPixel, NULL);
	XSetForeground(pDisplay, defGC, backPixel);
	XFillRectangle(pDisplay, window, defGC, nXPos, nYPos, nWidth, nHeight);

	XSetForeground(pDisplay, defGC, BlackPixel(pDisplay, nScreenNo));
	XDrawRectangle(pDisplay, window, defGC, nXPos, nYPos, nWidth-1, nHeight-1);

	SetRectangle(&rcFrame, 1, 1, nWidth-2, nHeight-2);
	DrawButtonFrame(gVKData.wdtVKArea, &rcFrame, FALSE, 1);
}

void KeyboardAux_DrawKeyButton(int nKeyButtonID, int bPushed)
{
	Display* pDisplay = XtDisplay(gVKData.wdtShell);
	int nScreenNo = DefaultScreen(pDisplay);
	GC defGC = DefaultGC(pDisplay, nScreenNo);
	Window window = XtWindow(gVKData.wdtVKArea);
	XmFontList fontList = gVKData.fontlist_ctrl;
	XRectangle rcFrame;
	Pixel backPixel, forePixel;
	int nWordWidth, nWordHeight;
	int nXPos, nYPos, nWidth, nHeight, i;
	char label_str[2], *keylist_label, *str; 
	XmString xmstr_base;
	XRectangle *KeyButtonFrame = gVKData.KeyButtonFrame;
	VirtualKeyboard *pVKB;
	
	if (gVKB[gVKData.nKeyboardID])
		pVKB = gVKB[gVKData.nKeyboardID];
	else
		pVKB = gVKB[0];

	nXPos = KeyButtonFrame[nKeyButtonID].x;
	nYPos = KeyButtonFrame[nKeyButtonID].y;
	nWidth = KeyButtonFrame[nKeyButtonID].width;
	nHeight = KeyButtonFrame[nKeyButtonID].height;

	if (bPushed == TRUE) {
		XtVaGetValues(gVKData.wdtVKArea, XmNbottomShadowColor, &backPixel, NULL);
	} else {
		XtVaGetValues(gVKData.wdtVKArea, XmNbackground, &backPixel, NULL);
	}

	XSetForeground(pDisplay, defGC, backPixel);
	XFillRectangle(pDisplay, window, defGC, nXPos, nYPos, nWidth, nHeight);

	XtVaGetValues(gVKData.wdtVKArea, XmNforeground, &forePixel, NULL);
	XSetForeground(pDisplay, defGC,  forePixel);
	XSetBackground(pDisplay, defGC,  backPixel);

	keylist_label = (char *)KEYLIST_LABEL;

	if (nKeyButtonID >= MAX_BASEKEY_NUM) {
		/* if is Control Keys */

		str = pVKB->ctrlkey[nKeyButtonID-MAX_BASEKEY_NUM].label_str;
		if (str == NULL) return;

		xmstr_base = XmStringCreate(str, "TAG1");
		nWordHeight = XmStringHeight(fontList, xmstr_base);
		nWordWidth  = XmStringWidth(fontList, xmstr_base);
		nXPos = nXPos + (nWidth - nWordWidth)/2;
		nYPos = nYPos + (nHeight - nWordHeight)/2;
		XmStringDraw(pDisplay, window, fontList, xmstr_base, defGC, 
				nXPos, nYPos, nWidth, 
				XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, NULL);
		XmStringFree(xmstr_base);

	} else {
		/* if is Base Keys */

		/* if is PC Keyboard */
		if (gVKData.nKeyboardID != 0 && gVKData.nKeyboardID != gKeyboardNum) {
			label_str[0] = *(keylist_label + nKeyButtonID);
			label_str[1] = 0;

			XmbDrawImageString(pDisplay, window, gVKData.fontset_normal, defGC, 
				nXPos + 3, nYPos + 15, label_str, 1);
		}

		str = pVKB->basekey[nKeyButtonID].lower_str;
		if (str && *str) {
			XmbDrawImageString(pDisplay, window, gVKData.fontset_normal, defGC, 
					nXPos + 3, nYPos + 29,
					str, strlen(str));
		}

		str = pVKB->basekey[nKeyButtonID].upper_str;
		if (str && *str) {
			if (str[1]) {
				/* if is not English Character */
				nXPos = nXPos + nWidth - 13;
			} else {
				/* if is English character */
				nXPos = nXPos + nWidth - 10;
			}
			XmbDrawImageString(pDisplay, window, gVKData.fontset_normal, defGC, 
					nXPos, nYPos + 14,
					str, strlen(str));
		}
	}

	DrawButtonFrame(gVKData.wdtVKArea, &(KeyButtonFrame[nKeyButtonID]), bPushed, 2);
}

void KeyboardAux_DrawAllCtrlKeyButtons()
{
	int nKeyButtonID, nCtrlKeyID, bPushed;

	for (nKeyButtonID=MAX_BASEKEY_NUM; nKeyButtonID<MAX_VK_NUM; nKeyButtonID++) {

		bPushed = FALSE;

		nCtrlKeyID = nKeyButtonID - MAX_BASEKEY_NUM;
		if (nCtrlKeyID == VK_Caps_Lock) {
			bPushed = gVKData.nCapsLockKey_Status ? TRUE : FALSE;
		} else if (nCtrlKeyID == VK_Control_L) {
			bPushed = gVKData.nCtrlKey_Status ? TRUE : FALSE;
		} else if (nCtrlKeyID == VK_Shift_L) {
			bPushed = gVKData.nShiftKey_Status ? TRUE : FALSE;
		} else if (nCtrlKeyID == VK_Alt_L) {
			bPushed = gVKData.nAltKey_Status ? TRUE : FALSE;
		}
		KeyboardAux_DrawKeyButton(nKeyButtonID, bPushed);
	}
}

void KeyboardAux_DrawAllButtons()
{
	int nKeyButtonID, nCtrlKeyID, bPushed;

	KeyboardAux_DrawKeyboardFrame();

	for (nKeyButtonID=0; nKeyButtonID<MAX_VK_NUM; nKeyButtonID++) {
		bPushed = FALSE;
		if (nKeyButtonID >= MAX_BASEKEY_NUM) {
			/* if is Control Keys */
			nCtrlKeyID = nKeyButtonID - MAX_BASEKEY_NUM;
			if (nCtrlKeyID == VK_Caps_Lock) {
				bPushed = gVKData.nCapsLockKey_Status ? TRUE : FALSE;
			} else if (nCtrlKeyID == VK_Control_L) {
				bPushed = gVKData.nCtrlKey_Status ? TRUE : FALSE;
			} else if (nCtrlKeyID == VK_Shift_L) {
				bPushed = gVKData.nShiftKey_Status ? TRUE : FALSE;
			} else if (nCtrlKeyID == VK_Alt_L) {
				bPushed = gVKData.nAltKey_Status ? TRUE : FALSE;
			}
		}
		KeyboardAux_DrawKeyButton(nKeyButtonID, bPushed);
	}
}

void KeyboardAux_UpdateStatus()
{
	Display* pDisplay = XtDisplay(gVKData.wdtShell);
	int nScreenNo = DefaultScreen(pDisplay);
	Window window = XtWindow(gVKData.wdtShell);
	Dimension nWidth, nHeight;
	int engine_id;

	DEBUG_printf("KeyboardAux_UpdateStatus: nKeyboardID:%d\n", gVKData.nKeyboardID);
	if (gVKData.nKeyboardID <= -1 || gVKData.nKeyboardID > gKeyboardNum) 
		gVKData.nKeyboardID = -1;

	if (gVKData.nKeyboardID == gKeyboardNum) {  
		engine_id = gVKData.nEngineID;
		if (engine_id >= 0 && engine_id < MAX_ENGINE_NUM) {
			gVKB[gKeyboardNum] = gIMEVKB[engine_id];
		} else {
			gVKB[gKeyboardNum] = NULL;
		}
	}

	if (gVKData.nKeyboardID == -1) {
		XtUnmapWidget(gVKData.wdtShell);
		return;
	}

	XtVaGetValues(gVKData.wdtShell, XmNwidth, &nWidth, XmNheight, &nHeight, NULL);
	if (gVKData.x == 0)
		gVKData.x = DisplayWidth(pDisplay, nScreenNo) - nWidth;
	if (gVKData.y == 0)
		gVKData.y = DisplayHeight(pDisplay, nScreenNo) - nHeight;

	XtVaSetValues(gVKData.wdtShell, XmNx, gVKData.x, XmNy, gVKData.y, NULL);

	KeyboardAux_DrawAllButtons();
	XtMapWidget(gVKData.wdtShell);
	xaux_ext_skip_taskbar_hint(pDisplay, window, True);
	XRaiseWindow(pDisplay, window);
	XFlush(pDisplay);
}

void KeyboardAux_Hide()
{
	XtUnmapWidget(gVKData.wdtShell);
}

void KeyboardAux_Clear_CtrlKey_Status()
{
	gVKData.nCtrlKey_Status = 0;
	gVKData.nShiftKey_Status = 0;
	gVKData.nAltKey_Status = 0;
}

void KeyboardAux_Get_CtrlKey_Status(int *nKeyStatus)
{
	int nTmp_Status = 0;

/*
	if (gVKData.nCtrlKey_Status) 
		nTmp_Status |= (1 << 0);
	if (gVKData.nShiftKey_Status) 
		nTmp_Status |= (1 << 1);
	if (gVKData.nAltKey_Status) 
		nTmp_Status |= (1 << 2);
*/
	if (gVKData.nCapsLockKey_Status) 
		nTmp_Status |= (1 << 3);

	*nKeyStatus = nTmp_Status;
}

void KeyboardAux_Set_CtrlKey_Status(int nKeyStatus)
{
	gVKData.nCtrlKey_Status = (nKeyStatus >> 0) & 1;
	gVKData.nShiftKey_Status = (nKeyStatus >> 1) & 1;
	gVKData.nAltKey_Status = (nKeyStatus >> 2) & 1;
	gVKData.nCapsLockKey_Status = (nKeyStatus >> 3) & 1;
}

static int KeyCodeOfBaseKey_List[MAX_BASEKEY_NUM] = {
	IM_VK_BACK_QUOTE,
	IM_VK_1,
	IM_VK_2,
	IM_VK_3,
	IM_VK_4,
	IM_VK_5,
	IM_VK_6,
	IM_VK_7,
	IM_VK_8,
	IM_VK_9,
	IM_VK_0,
	IM_VK_MINUS,
	IM_VK_EQUALS,

	IM_VK_Q,
	IM_VK_W,
	IM_VK_E,
	IM_VK_R,
	IM_VK_T,
	IM_VK_Y,
	IM_VK_U,
	IM_VK_I,
	IM_VK_O,
	IM_VK_P,
	IM_VK_OPEN_BRACKET,
	IM_VK_CLOSE_BRACKET,
	IM_VK_BACK_SLASH,

	IM_VK_A,
	IM_VK_S,
	IM_VK_D,
	IM_VK_F,
	IM_VK_G,
	IM_VK_H,
	IM_VK_J,
	IM_VK_K,
	IM_VK_L,
	IM_VK_SEMICOLON,
	IM_VK_QUOTE,

	IM_VK_Z,
	IM_VK_X,
	IM_VK_C,
	IM_VK_V,
	IM_VK_B,
	IM_VK_N,
	IM_VK_M,
	IM_VK_COMMA,
	IM_VK_PERIOD,
	IM_VK_SLASH,
};

static int KeyCodeOfCtrlKey_List[MAX_CTRLKEY_NUM] = {
	IM_VK_BACK_SPACE,
	IM_VK_TAB,
	IM_VK_CAPS_LOCK,
	IM_VK_ENTER,
	0,
	0,
	0,
	IM_VK_SPACE,
	IM_VK_ESCAPE
};
	
int  KeyboardAux_Get_KeyButton_From_Keycode(int nKeyCode, int nKeyChar)
{
	int nKeyButtonID, i;

	nKeyButtonID = -1;

	if (nKeyChar == 0) {
		/* if is Ctrl Keys */
		for (i=0; i<MAX_CTRLKEY_NUM; i++) {
			if (nKeyCode == KeyCodeOfCtrlKey_List[i]) {
				nKeyButtonID = i + MAX_BASEKEY_NUM;
				break;
			}
		}
	} else {
		/* if is Base Keys */
		for (i=0; i<MAX_BASEKEY_NUM; i++) {
			if (nKeyCode == KeyCodeOfBaseKey_List[i]) {
				nKeyButtonID = i;
				break;
			}
		}
	}
	return(nKeyButtonID);
}

void KeyboardAux_Set_KeyEvent(int *nKeyCode, int *nKeyChar, int *nKeyStatus, int nKeyButtonID)
{
	int keycode, keychar, keystatus;
	char *keychar_list;

	keycode = 0; 
	keychar = 0;
	keystatus = 0;

	/* set keycode and keychar */
	if (nKeyButtonID >= MAX_BASEKEY_NUM) {
		keycode = KeyCodeOfCtrlKey_List[nKeyButtonID - MAX_BASEKEY_NUM];
		keychar = 0;
		if (nKeyButtonID - MAX_BASEKEY_NUM == VK_space) {
			keychar = 0x20;
		}
	} else if (nKeyButtonID >= 0) {
		keycode = KeyCodeOfBaseKey_List[nKeyButtonID];

		keychar_list = (char *)KEYLIST_LOWER;
		if (gVKData.nCapsLockKey_Status ^ gVKData.nShiftKey_Status) 
			keychar_list = (char *)KEYLIST_UPPER;

		keychar = *(keychar_list + nKeyButtonID);
	}

	/* set keystatus */
	if (gVKData.nCtrlKey_Status) 
		keystatus |= IM_CTRL_MASK;
	if (gVKData.nShiftKey_Status) 
		keystatus |= IM_SHIFT_MASK;
	if (gVKData.nAltKey_Status) 
		keystatus |= IM_ALT_MASK;

	DEBUG_printf("Create Key Event: keycode:0x%x, keychar:0x%x, keystatus:0x%x\n",
		keycode, keychar, keystatus);
	*nKeyCode = keycode;
	*nKeyChar = keychar;
	*nKeyStatus = keystatus;
}

void KeyboardAux_Press_Key(int nKeyButtonID)
{
	VirtualKeyboard *pVKB;
	char *str, *keylist_label, base_str[2];
	int nCtrlKeyID, nKeyCode, nKeyChar, nKeyStatus;
	
	if (gVKData.nKeyboardID <= -1 || gVKData.nKeyboardID > gKeyboardNum) return;
	if (nKeyButtonID < 0 || nKeyButtonID >= MAX_VK_NUM) return;

	if (gVKB[gVKData.nKeyboardID])
		pVKB = gVKB[gVKData.nKeyboardID];
	else
		pVKB = gVKB[0];

	/* if is Control Keys, Set Key status or commit as virtual key */
	/* Only record Caps_lock Status */
	if (nKeyButtonID >= MAX_BASEKEY_NUM) {
		nCtrlKeyID = nKeyButtonID - MAX_BASEKEY_NUM;

		if (nCtrlKeyID == VK_BackSpace ||
			nCtrlKeyID == VK_Tab ||
			nCtrlKeyID == VK_Enter ||
			nCtrlKeyID == VK_space ||
			nCtrlKeyID == VK_escape) {
			/* if not Control status key, commit as key event */
			KeyboardAux_Set_KeyEvent(&nKeyCode, &nKeyChar, &nKeyStatus, nKeyButtonID);
			KeyboardAux_Commit_Key_Request(nKeyCode, nKeyChar, nKeyStatus);
			KeyboardAux_Clear_CtrlKey_Status();
		} else if (nCtrlKeyID == VK_Caps_Lock) {
			gVKData.nCapsLockKey_Status = gVKData.nCapsLockKey_Status ? 0 : 1;
		} else if (nCtrlKeyID == VK_Control_L) {
			gVKData.nCtrlKey_Status = gVKData.nCtrlKey_Status ? 0 : 1;
		} else if (nCtrlKeyID == VK_Shift_L) {
			gVKData.nShiftKey_Status = gVKData.nShiftKey_Status ? 0 : 1;
		} else if (nCtrlKeyID == VK_Alt_L) {
			gVKData.nAltKey_Status = gVKData.nAltKey_Status ? 0 : 1;
		}

		KeyboardAux_DrawAllCtrlKeyButtons();
		if (nCtrlKeyID == VK_Caps_Lock) {
			KeyboardAux_Get_CtrlKey_Status(&nKeyStatus);
			KeyboardAux_Change_Key_Status_Request(nKeyStatus);
		}

		return;
	}

	/* if is Base Keys */
	DEBUG_printf("Keyboard Type: %d, KEYBOARD_KEY_TYPE:%d\n", pVKB->type, KEYBOARD_KEY_TYPE);
	if (pVKB->type == KEYBOARD_KEY_TYPE) {
		KeyboardAux_Set_KeyEvent(&nKeyCode, &nKeyChar, &nKeyStatus, nKeyButtonID);
		KeyboardAux_Commit_Key_Request(nKeyCode, nKeyChar, nKeyStatus);
	} else {
		if (gVKData.nCtrlKey_Status || gVKData.nAltKey_Status) {
			KeyboardAux_Set_KeyEvent(&nKeyCode, &nKeyChar, &nKeyStatus, nKeyButtonID);
			DEBUG_printf("Before commit key: nKeyCode:0x%x, nKeyChar:0x%x, nKeyStatus:0x%x\n",
				nKeyCode, nKeyChar, nKeyStatus);
			KeyboardAux_Commit_Key_Request(nKeyCode, nKeyChar, nKeyStatus);
		} else {
			if (gVKData.nCapsLockKey_Status ^ gVKData.nShiftKey_Status) {
				str = pVKB->basekey[nKeyButtonID].upper_str;
				if (!str || !*str) {
					keylist_label = KEYLIST_UPPER;
					base_str[0] = *(keylist_label + nKeyButtonID);
					base_str[1] = 0;
					str = base_str;
				}
			} else {
				str = pVKB->basekey[nKeyButtonID].lower_str;
				if (!str || !*str) {
					keylist_label = KEYLIST_LOWER;
					base_str[0] = *(keylist_label + nKeyButtonID);
					base_str[1] = 0;
					str = base_str;
				}
			}
			KeyboardAux_Commit_String_Request(gLocaleID, str);
		}
	}

	KeyboardAux_Clear_CtrlKey_Status();
	KeyboardAux_DrawAllCtrlKeyButtons();

	return;
}

