/* ** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: WindowXlat.cpp /////////////////////////////////////////////////////// //----------------------------------------------------------------------------- // // Westwood Studios Pacific. // // Confidential Information // Copyright (C) 2001 - All Rights Reserved // //----------------------------------------------------------------------------- // // Project: RTS3 // // File name: WindowXlat.cpp // // Created: Colin Day, September 2001 // // Desc: Window system translator that monitors raw input messages // on the stream from the input devices and acts on anything // relevant to the windowing system. // //----------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////// // SYSTEM INCLUDES //////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine // USER INCLUDES ////////////////////////////////////////////////////////////// #include "Common/MessageStream.h" #include "GameClient/GameWindowManager.h" #include "GameClient/WindowXlat.h" #include "GameClient/Shell.h" #include "GameClient/Display.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif // DEFINES //////////////////////////////////////////////////////////////////// // PRIVATE TYPES ////////////////////////////////////////////////////////////// // PRIVATE DATA /////////////////////////////////////////////////////////////// // PUBLIC DATA //////////////////////////////////////////////////////////////// // PRIVATE PROTOTYPES ///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // PRIVATE FUNCTIONS ////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// #if defined(_DEBUG) || defined(_INTERNAL) //debug hack to view object under mouse stats extern ICoord2D TheMousePos; #endif // rawMouseToWindowMessage ==================================================== /** Translate a raw mouse input event to a game window specific message * for the window system */ //============================================================================= static GameWindowMessage rawMouseToWindowMessage( const GameMessage *msg ) { GameWindowMessage gwm = GWM_NONE; switch( msg->getType() ) { // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_POSITION: gwm = GWM_MOUSE_POS; break; // ------------------------------------------------------------------------ // Strange, but true. The window stuff really doesn't care about double clicks, so just // treat it as a down click.. Kinda like a second click. case GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: gwm = GWM_LEFT_DOWN; break; case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP: gwm = GWM_LEFT_UP; break; case GameMessage::MSG_RAW_MOUSE_LEFT_DRAG: gwm = GWM_LEFT_DRAG; break; // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN: gwm = GWM_MIDDLE_DOWN; break; case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP: gwm = GWM_MIDDLE_UP; break; case GameMessage::MSG_RAW_MOUSE_MIDDLE_DRAG: gwm = GWM_MIDDLE_DRAG; break; // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: gwm = GWM_RIGHT_DOWN; break; case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: gwm = GWM_RIGHT_UP; break; case GameMessage::MSG_RAW_MOUSE_RIGHT_DRAG: gwm = GWM_RIGHT_DRAG; break; // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_WHEEL: if( msg->getArgument( 1 )->integer > 0 ) gwm = GWM_WHEEL_UP; else gwm = GWM_WHEEL_DOWN; break; } // end switch return gwm; } // end rawMouseToWindowMessage /////////////////////////////////////////////////////////////////////////////// // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //============================================================================= WindowTranslator::WindowTranslator() { } //============================================================================= WindowTranslator::~WindowTranslator() { } // WindowTranslator =========================================================== /** Window translator that monitors raw input messages on the stream and * acts on anything relavant to the windowing system */ //============================================================================= GameMessageDisposition WindowTranslator::translateGameMessage(const GameMessage *msg) { GameMessageDisposition disp = KEEP_MESSAGE; Bool forceKeepMessage = FALSE; WinInputReturnCode returnCode = WIN_INPUT_NOT_USED; if (TheTacticalView && TheTacticalView->isMouseLocked()) { return KEEP_MESSAGE; } switch( msg->getType() ) { // ------------------------------------------------------------------------ case GameMessage::MSG_META_TOGGLE_ATTACKMOVE: { // Basically, we're cheating here. The mouse no longer sends us useless spam. ICoord2D mousePos = TheMouse->getMouseStatus()->pos; if( TheWindowManager ) TheWindowManager->winProcessMouseEvent( GWM_NONE, &mousePos, NULL ); // Force it to keep the message, regardless of what the window thinks it did with the input. return KEEP_MESSAGE; } // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP: { if( TheInGameUI && TheInGameUI->isPlacementAnchored() ) { //If we release the button outside forceKeepMessage = TRUE; } //FALL THROUGH INTENTIONALLY! } case GameMessage::MSG_RAW_MOUSE_POSITION: case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: case GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN: case GameMessage::MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP: case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: { // all window events have the position of the mouse as arg 0 ICoord2D mousePos = msg->getArgument( 0 )->pixel; #if defined(_DEBUG) || defined(_INTERNAL) //debug hack to view object under mouse stats TheMousePos.x = mousePos.x; TheMousePos.y = mousePos.y; #endif // process the mouse event position GameWindowMessage gwm = rawMouseToWindowMessage( msg ); if( TheWindowManager ) returnCode = TheWindowManager->winProcessMouseEvent( gwm, &mousePos, NULL ); if( TheShell && TheShell->isShellActive() ) returnCode = WIN_INPUT_USED; if ( TheInGameUI && TheInGameUI->getInputEnabled() == FALSE ) returnCode = WIN_INPUT_USED; break; } // end, raw mouse position // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_LEFT_DRAG: case GameMessage::MSG_RAW_MOUSE_MIDDLE_DRAG: case GameMessage::MSG_RAW_MOUSE_RIGHT_DRAG: { // all window events have the position of the mouse as arg 0 ICoord2D mousePos = msg->getArgument( 0 )->pixel; // get delta for drag ICoord2D delta = msg->getArgument( 1 )->pixel; // process drag event GameWindowMessage gwm = rawMouseToWindowMessage( msg ); if( TheWindowManager ) returnCode = TheWindowManager->winProcessMouseEvent( gwm, &mousePos, &delta ); if( TheShell && TheShell->isShellActive() ) returnCode = WIN_INPUT_USED; if ( TheInGameUI && TheInGameUI->getInputEnabled() == FALSE ) returnCode = WIN_INPUT_USED; break; } // end drag mouse // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_MOUSE_WHEEL: { // all window events have the position of the mouse as arg 0 ICoord2D mousePos = msg->getArgument( 0 )->pixel; // get wheel position Int wheelPos = msg->getArgument( 1 )->integer; // process wheel event GameWindowMessage gwm = rawMouseToWindowMessage( msg ); if( TheWindowManager ) returnCode = TheWindowManager->winProcessMouseEvent( gwm, &mousePos, &wheelPos ); if( TheShell && TheShell->isShellActive() ) returnCode = WIN_INPUT_USED; if ( TheInGameUI && TheInGameUI->getInputEnabled() == FALSE ) returnCode = WIN_INPUT_USED; break; } // end mouse wheel // ------------------------------------------------------------------------ case GameMessage::MSG_RAW_KEY_DOWN: case GameMessage::MSG_RAW_KEY_UP: { // get key and state from args UnsignedByte key = msg->getArgument( 0 )->integer; UnsignedByte state = msg->getArgument( 1 )->integer; // process event through window system if( TheWindowManager ) returnCode = TheWindowManager->winProcessKey( key, state ); // If we're in a movie, we want to be able to escape out of it if(returnCode != WIN_INPUT_USED && (key == KEY_ESC) && (BitTest( state, KEY_STATE_UP )) && TheDisplay->isMoviePlaying() && TheGlobalData->m_allowExitOutOfMovies == TRUE ) { TheDisplay->stopMovie(); returnCode = WIN_INPUT_USED; } if(returnCode != WIN_INPUT_USED && (key == KEY_ESC) && (BitTest( state, KEY_STATE_UP )) && (TheInGameUI && (TheInGameUI->getInputEnabled() == FALSE)) ) { returnCode = WIN_INPUT_USED; } break; } // end key messages // ------------------------------------------------------------------------ default: break; } // end switch( msg->getType() ) // remove event from the stream if the return code specifies to do so // If TheShell doesn't exist, then well, we're not in RTS, we're in GUIEdit if( returnCode == WIN_INPUT_USED && !forceKeepMessage )// || (TheShell && TheShell->isShellActive())) { disp = DESTROY_MESSAGE; } return disp; }