//--------------------------------------------------------------------------- // // MechCommander 2 // // UserInput Class -- Polls the state of keyboard, mouse, joystick // for this frame and stores values. // //---------------------------------------------------------------------------// // Copyright (C) Microsoft Corporation. All rights reserved. // //===========================================================================// #ifndef USERINPUT_H #include "userinput.h" #endif #ifndef TIMING_H #include "timing.h" #endif #ifndef CIDENT_H #include "cident.h" #endif #ifndef INIFILE_H #include "inifile.h" #endif #ifndef PATHS_H #include "paths.h" #endif #ifndef CLIP_H #include "clip.h" #endif #ifndef TXMMGR_H #include "txmmgr.h" #endif #include #include #include //--------------------------------------------------------------------------- UserInput *userInput = NULL; extern bool hasGuardBand; volatile bool UserInput::drawMouse = false; extern volatile bool mc2IsInDisplayBackBuffer; extern volatile bool mc2IsInMouseTimer; void MouseTimerInit(); void MouseTimerKill(); //--------------------------------------------------------------------------- void MouseCursorData::initCursors (char *cursorFileName) { //New // add an "a" to the end of the cursorFileName IF we are running in 800x600 or less. // Loads different sized cursors. char realHackName[1024]; strcpy(realHackName,cursorFileName); if (Environment.screenWidth <= 800) sprintf(realHackName,"%sa",cursorFileName); FullPathFileName cursorName; cursorName.init(artPath,realHackName,".fit"); FitIniFile cursorFile; long result = cursorFile.open(cursorName); gosASSERT(result == NO_ERR); result = cursorFile.seekBlock("Main"); gosASSERT(result == NO_ERR); result = cursorFile.readIdLong("NumCursors",numCursors); gosASSERT(result == NO_ERR); gosASSERT( numCursors < MAX_MOUSE_STATES ); cursorInfos = new StaticInfo[numCursors]; //---------------------------------------------- // Each cursor is defined as a number of frames // and a TGA File Name which we use to create // the texture handle. char blockName[32]; for (long i=0;imouseOff(); if ( cursorInfos ) { delete [] cursorInfos; cursorInfos = NULL; } numCursors = 0; } } //--------------------------------------------------------------------------- void UserInput::mouseOn (void) //Draw Mouse Cursor { drawMouse = true; } void UserInput::mouseOff (void) //Don't Draw Mouse Cursor { drawMouse = false; } void UserInput::setMouseCursor (long state) { if ((state < 0) || (state >= mState_NUMMOUSESTATES)) return; //DEBUG!!!!!!!!!!!!!!!!!!!!!! if (state == mState_NORMAL) printf("Go Flash"); mouseState = state; } //--------------------------------------------------------------------------- void UserInput::update (void) { if (mc2UseAsyncMouse && !mc2MouseThreadStarted) MouseTimerInit(); if (!mc2UseAsyncMouse && mc2MouseThreadStarted) MouseTimerKill(); //----------------------------- // Save the last Mouse States lastLeftMouseButtonState = leftMouseButtonState; lastRightMouseButtonState = rightMouseButtonState; lastMouseXPosition = mouseXPosition; lastMouseYPosition = mouseYPosition; leftMouseJustUp = 0; rightMouseJustUp = 0; bool bWasDouble = leftDoubleClick; //------------------------------------------------------ // Reset Frame dependant variables leftClick = rightClick = middleClick = false; leftDoubleClick = rightDoubleClick = middleDoubleClick = false; DWORD LEFT_MOUSE_CODE = VK_LBUTTON; DWORD RIGHT_MOUSE_CODE = VK_RBUTTON; if ( GetSystemMetrics(SM_SWAPBUTTON) ) { RIGHT_MOUSE_CODE = VK_LBUTTON; LEFT_MOUSE_CODE = VK_RBUTTON; } //----------------- // Poll the mouse. DWORD buttonStates; gos_GetMouseInfo(&mouseXPosition,&mouseYPosition,(int *)&mouseXDelta,(int *)&mouseYDelta,(int *)&mouseWheelDelta,&buttonStates); // leftMouseButtonState = buttonStates & 1; // rightMouseButtonState = (buttonStates & 2) >> 1; // middleMouseButtonState = (buttonStates & 4) >> 2; SHORT code = GetAsyncKeyState(LEFT_MOUSE_CODE); SHORT rCode = GetAsyncKeyState( RIGHT_MOUSE_CODE ); SHORT mCode = GetAsyncKeyState( VK_MBUTTON ); leftMouseButtonState = code ? MC2_MOUSE_DOWN : MC2_MOUSE_UP; rightMouseButtonState = rCode ? MC2_MOUSE_DOWN : MC2_MOUSE_UP; middleMouseButtonState = mCode ? MC2_MOUSE_DOWN : MC2_MOUSE_UP; //--------------------------------------------------------- // Adjust MouseWheelDelta to get old Broken Win2K values. mouseWheelDelta *= -100; //------------------------------------- // Determine drag, double click states if ((leftMouseButtonState == MC2_MOUSE_UP) && (lastLeftMouseButtonState == MC2_MOUSE_DOWN)) { //-------------------------------------------------------------------- // Just lifted the button. Drags are OFF! Double Click clock starts! wasLeftMouseDrag = leftMouseDrag; wasRightMouseDrag = rightMouseDrag; leftMouseDrag = false; mouseLeftUpTime += frameLength; // if ( !bWasDouble ) leftMouseJustUp = 1; mouseLeftHeldTime = 0.f; } if ((leftMouseButtonState == MC2_MOUSE_UP) && (lastLeftMouseButtonState == MC2_MOUSE_UP)) { //-------------------------------------------- // We are still up. Increment mouse up time. mouseLeftUpTime += frameLength; mouseLeftHeldTime = 0.f; } if ( gos_GetKeyStatus( KEY_LMOUSE ) == KEY_PRESSED /*code & 0x0001*/ ) // clicked { //------------------------------------------------------------------------------- // We just clicked down. If mouseUpTime is < threshold, this was a double click if ( (mouseLeftUpTime > 0.0 ) && (mouseLeftUpTime < mouseDblClickThreshold) && !bWasDouble) { leftDoubleClick = true; mouseLeftUpTime = 0.f; // make sure if we hold it, we don't keep clicking } else { leftClick = true; mouseLeftUpTime = 0.001f; } mouseDragX = lastMouseXPosition; mouseDragY = lastMouseYPosition; leftMouseDrag = 0; } else if (gos_GetKeyStatus( KEY_LMOUSE ) == KEY_HELD /*code & 0x8000*/) // held { mouseLeftUpTime = 5.0; //----------------------------------------------------------------------- // Down and still down should indicate dragging. Check threshold of // Deltas to see if this is TRUE IF AND ONLY IF we are NOT yet DRAGGING! if (!leftMouseDrag) { if ((fabs(mouseDragX - mouseXPosition) > mouseDragThreshold) || (fabs(mouseDragY - mouseYPosition) > mouseDragThreshold)) { //------------------ // We are dragging. leftMouseDrag = true; } } mouseLeftUpTime = 0; mouseLeftHeldTime += frameLength; } if ((rightMouseButtonState == MC2_MOUSE_UP) && (lastRightMouseButtonState == MC2_MOUSE_DOWN)) { //-------------------------------------------------------------------- // Just lifted the button. Drags are OFF! Double Click clock starts! wasRightMouseDrag = rightMouseDrag; rightMouseDrag = false; mouseRightUpTime = 0.001f; rightMouseJustUp = true; mouseRightHeldTime = 0.f; } if ((rightMouseButtonState == MC2_MOUSE_UP) && (lastRightMouseButtonState == MC2_MOUSE_UP)) { //-------------------------------------------- // We are still up. Increment mouse up time. mouseRightUpTime += frameLength; rightMouseDrag = 0; mouseRightHeldTime = 0.f; } if (gos_GetKeyStatus( KEY_RMOUSE ) == KEY_PRESSED /*rCode & 0x0001*/) { //------------------------------------------------------------------------------- // We just clicked down. If mouseUpTime is < threshold, this was a double click if (mouseRightUpTime && mouseRightUpTime < mouseDblClickThreshold) rightDoubleClick = true; else rightClick = true; mouseDragX = lastMouseXPosition; mouseDragY = lastMouseYPosition; rightMouseDrag = 0; } else if (gos_GetKeyStatus( KEY_RMOUSE ) == KEY_HELD /*rCode & 0x8000*/) { //----------------------------------------------------------------------- // Down and still down should indicate dragging. Check threshold of // Deltas to see if this is TRUE IF AND ONLY IF we are NOT yet DRAGGING! if (!rightMouseDrag) { if ((fabs(mouseDragX - mouseXPosition) > mouseDragThreshold) || (fabs(mouseDragY - mouseYPosition) > mouseDragThreshold)) { //------------------ // We are dragging. rightMouseDrag = true; } } rightClick = true; mouseRightUpTime = 0; mouseRightHeldTime += frameLength; } if ((middleMouseButtonState == MC2_MOUSE_UP) && (lastMiddleMouseButtonState == MC2_MOUSE_DOWN)) { //-------------------------------------------------------------------- // Just lifted the button. Drags are OFF! Double Click clock starts! mouseMiddleUpTime = 0.0; } if ((middleMouseButtonState == MC2_MOUSE_UP) && (lastMiddleMouseButtonState == MC2_MOUSE_UP)) { //-------------------------------------------- // We are still up. Increment mouse up time. mouseMiddleUpTime += frameLength; } if (gos_GetKeyStatus( KEY_MMOUSE ) == KEY_PRESSED /*mCode & 0x0001*/) { //------------------------------------------------------------------------------- // We just clicked down. If mouseUpTime is < threshold, this was a double click if (mouseMiddleUpTime < mouseDblClickThreshold) middleDoubleClick = true; else middleClick = true; } if (cursors->getNumFrames( mouseState ) > 1 ) { mouseFrameLength += frameLength; if (mouseFrameLength > cursors->frameLengths[mouseState] ) { mouseFrame++; if (mouseFrame >= cursors->getNumFrames(mouseState)) { mouseFrame = 0; } mouseFrameLength = 0.0; } } if (mc2UseAsyncMouse) { //Wait for thread to finish. Otherwise, we may move its data buffer halfway through!! while (mc2IsInMouseTimer) ; //ONLY set the mouse BLT data at the end of each update. NO MORE FLICKERING THEN!!! // BLOCK THREAD WHILE THIS IS HAPPENING mc2IsInDisplayBackBuffer = true; if (!mc2MouseData) { mc2MouseData = (MemoryPtr)malloc(sizeof(DWORD) * MOUSE_WIDTH * MOUSE_WIDTH); memset(mc2MouseData,0,sizeof(DWORD) * MOUSE_WIDTH * MOUSE_WIDTH); } //Need to update the mouse in the mouse thread to inform it that the cursor // possibly changed size and shape. mc2MouseHotSpotX = cursors->getMouseHSX( mouseState ); mc2MouseHotSpotY = cursors->getMouseHSY( mouseState ); mc2MouseWidth = cursors->cursorInfos[mouseState].width(); mc2MouseHeight = cursors->cursorInfos[mouseState].height(); DWORD totalMouseFrames = cursors->getNumFrames(mouseState); if ( totalMouseFrames > 1 ) { long framesPerRow = cursors->cursorInfos[mouseState].textureWidth/cursors->cursorInfos[mouseState].width(); int iIndex = mouseFrame % framesPerRow; int jIndex = mouseFrame / framesPerRow; float oldU = cursors->cursorInfos[mouseState].u; float oldV = cursors->cursorInfos[mouseState].v; float newU = (.1f + oldU)/cursors->cursorInfos[mouseState].textureWidth + ((float)iIndex * cursors->cursorInfos[mouseState].width()/cursors->cursorInfos[mouseState].textureWidth); float newV = (.1f + oldV)/cursors->cursorInfos[mouseState].textureWidth + (float)jIndex * cursors->cursorInfos[mouseState].height()/cursors->cursorInfos[mouseState].textureWidth; float newU2 = newU + (cursors->cursorInfos[mouseState].width() + .1)/cursors->cursorInfos[mouseState].textureWidth; float newV2 = newV + (cursors->cursorInfos[mouseState].height() + .1)/cursors->cursorInfos[mouseState].textureWidth; cursors->cursorInfos[mouseState].setNewUVs( newU, newV, newU2, newV2 ); cursors->cursorInfos[mouseState].getData(mc2MouseData); cursors->cursorInfos[mouseState].u = oldU; cursors->cursorInfos[mouseState].v = oldV; } else if (totalMouseFrames) { cursors->cursorInfos[mouseState].getData(mc2MouseData); } //Unblock Thread mc2IsInDisplayBackBuffer = false; } } //--------------------------------------------------------------------------- void UserInput::initMouseCursors (char *mouseFile) { if (cursors) { cursors->destroy(); delete cursors; cursors = NULL; } cursors = new MouseCursorData; gosASSERT(cursors != NULL); cursors->initCursors(mouseFile); mouseFrame = 0; } //--------------------------------------------------------------------------- float smallTextureTLUVX[4] = { 0.00, 0.50, 0.00, 0.50 }; float smallTextureTLUVY[4] = { 0.00, 0.00, 0.50, 0.50 }; float smallTextureBRUVX[4] = { 0.50, 1.00, 0.50, 1.00 }; float smallTextureBRUVY[4] = { 0.50, 0.50, 1.00, 1.00 }; //--------------------------------------------------------------------------- float mediumTextureTLUVX[16] = { 0.00, 0.25, 0.50, 0.75, 0.00, 0.25, 0.50, 0.75, 0.00, 0.25, 0.50, 0.75, 0.00, 0.25, 0.50, 0.75 }; float mediumTextureTLUVY[16] = { 0.00, 0.00, 0.00, 0.00, 0.25, 0.25, 0.25, 0.25, 0.50, 0.50, 0.50, 0.50, 0.75, 0.75, 0.75, 0.75 }; float mediumTextureBRUVX[16] = { 0.25, 0.50, 0.75, 1.00, 0.25, 0.50, 0.75, 1.00, 0.25, 0.50, 0.75, 1.00, 0.25, 0.50, 0.75, 1.00 }; float mediumTextureBRUVY[16] = { 0.25, 0.25, 0.25, 0.25, 0.50, 0.50, 0.50, 0.50, 0.75, 0.75, 0.75, 0.75, 1.00, 1.00, 1.00, 1.00 }; //--------------------------------------------------------------------------- float largeTextureTLUVX[64] = { 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 0.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875 }; float largeTextureTLUVY[64] = { 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.875, 0.875, 0.875, 0.875, 0.875, 0.875, 0.875, 0.875 }; float largeTextureBRUVX[64] = { 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00, 0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875, 1.00 }; float largeTextureBRUVY[64] = { 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.625, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.875, 0.875, 0.875, 0.875, 0.875, 0.875, 0.875, 0.875, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 }; //--------------------------------------------------------------------------- void UserInput::setMouseScale (float scaleFactor) { if (scaleFactor > 0.0f) mouseScale = scaleFactor; } //--------------------------------------------------------------------------- void UserInput::render (void) //Last thing rendered. Draws Mouse. { if (!mc2UseAsyncMouse) { if (drawMouse && mouseState != -1) { // figure out where to put the thing long mouseX = getMouseX(); long mouseY = getMouseY(); mouseX -= cursors->getMouseHSX( mouseState ); mouseY -= cursors->getMouseHSY( mouseState ); cursors->cursorInfos[mouseState].setLocation( mouseX, mouseY ); long totalMouseFrames = cursors->getNumFrames(mouseState); if ( totalMouseFrames > 1 ) { long framesPerRow = cursors->cursorInfos[mouseState].textureWidth/cursors->cursorInfos[mouseState].width(); int iIndex = mouseFrame % framesPerRow; int jIndex = mouseFrame / framesPerRow; float oldU = cursors->cursorInfos[mouseState].u; float oldV = cursors->cursorInfos[mouseState].v; float newU = (.1f + oldU)/cursors->cursorInfos[mouseState].textureWidth + ((float)iIndex * cursors->cursorInfos[mouseState].width()/cursors->cursorInfos[mouseState].textureWidth); float newV = (.1f + oldV)/cursors->cursorInfos[mouseState].textureWidth + (float)jIndex * cursors->cursorInfos[mouseState].height()/cursors->cursorInfos[mouseState].textureWidth; float newU2 = newU + (cursors->cursorInfos[mouseState].width() + .1)/cursors->cursorInfos[mouseState].textureWidth; float newV2 = newV + (cursors->cursorInfos[mouseState].height() + .1)/cursors->cursorInfos[mouseState].textureWidth; cursors->cursorInfos[mouseState].setNewUVs( newU, newV, newU2, newV2 ); cursors->cursorInfos[mouseState].render(); cursors->cursorInfos[mouseState].u = oldU; cursors->cursorInfos[mouseState].v = oldV; } else cursors->cursorInfos[mouseState].render(); } } } //---------------------------------------------------------------------------