/* ** Command & Conquer Renegade(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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Combat * * * * $Archive:: /Commando/Code/commando/dlgcontrolslisttab.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 1/17/02 11:22a $* * * * $Revision:: 11 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "dlgcontrolslisttab.h" #include "inputctrl.h" #include "input.h" #include "dlgcontrols.h" #include "string_ids.h" #include "translatedb.h" #define DIRECTINPUT_VERSION 0x0800 #include #include "directinput.h" //////////////////////////////////////////////////////////////// // Local constants //////////////////////////////////////////////////////////////// typedef struct { int function_id; int name_id; } INPUT_FUNCTION_NAME; const INPUT_FUNCTION_NAME FUNCTION_NAMES[] = { { INPUT_FUNCTION_MOVE_FORWARD, IDS_FUNCTION_MOVE_FORWARD }, { INPUT_FUNCTION_MOVE_BACKWARD, IDS_FUNCTION_MOVE_BACKWARD }, { INPUT_FUNCTION_MOVE_LEFT, IDS_FUNCTION_MOVE_LEFT }, { INPUT_FUNCTION_MOVE_RIGHT, IDS_FUNCTION_MOVE_RIGHT }, { INPUT_FUNCTION_TURN_LEFT, IDS_FUNCTION_TURN_LEFT }, { INPUT_FUNCTION_TURN_RIGHT, IDS_FUNCTION_TURN_RIGHT }, { INPUT_FUNCTION_WALK_MODE, IDS_FUNCTION_WALK_MODE }, { INPUT_FUNCTION_JUMP, IDS_FUNCTION_JUMP }, { INPUT_FUNCTION_CROUCH, IDS_FUNCTION_CROUCH }, { INPUT_FUNCTION_ACTION, IDS_FUNCTION_ACTION }, { INPUT_FUNCTION_TURN_AROUND, IDS_FUNCTION_TURN_AROUND }, { INPUT_FUNCTION_FIRE_WEAPON_PRIMARY, IDS_FUNCTION_FIRE_WEAPON_PRIMARY }, { INPUT_FUNCTION_FIRE_WEAPON_SECONDARY, IDS_FUNCTION_FIRE_WEAPON_SECONDARY }, { INPUT_FUNCTION_PREV_WEAPON, IDS_FUNCTION_PREV_WEAPON }, { INPUT_FUNCTION_NEXT_WEAPON, IDS_FUNCTION_NEXT_WEAPON }, { INPUT_FUNCTION_RELOAD_WEAPON, IDS_FUNCTION_RELOAD_WEAPON }, { INPUT_FUNCTION_ZOOM_IN, IDS_FUNCTION_ZOOM_IN }, { INPUT_FUNCTION_ZOOM_OUT, IDS_FUNCTION_ZOOM_OUT }, { INPUT_FUNCTION_SELECT_WEAPON_1, IDS_FUNCTION_SELECT_WEAPON_1 }, { INPUT_FUNCTION_SELECT_WEAPON_2, IDS_FUNCTION_SELECT_WEAPON_2 }, { INPUT_FUNCTION_SELECT_WEAPON_3, IDS_FUNCTION_SELECT_WEAPON_3 }, { INPUT_FUNCTION_SELECT_WEAPON_4, IDS_FUNCTION_SELECT_WEAPON_4 }, { INPUT_FUNCTION_SELECT_WEAPON_5, IDS_FUNCTION_SELECT_WEAPON_5 }, { INPUT_FUNCTION_SELECT_WEAPON_6, IDS_FUNCTION_SELECT_WEAPON_6 }, { INPUT_FUNCTION_SELECT_WEAPON_7, IDS_FUNCTION_SELECT_WEAPON_7 }, { INPUT_FUNCTION_SELECT_WEAPON_8, IDS_FUNCTION_SELECT_WEAPON_8 }, { INPUT_FUNCTION_SELECT_WEAPON_9, IDS_FUNCTION_SELECT_WEAPON_9 }, { INPUT_FUNCTION_SELECT_WEAPON_0, IDS_FUNCTION_SELECT_WEAPON_0 }, { INPUT_FUNCTION_CURSOR_TARGETING, IDS_FUNCTION_CURSOR_TARGETING }, { INPUT_FUNCTION_FIRST_PERSON_TOGGLE, IDS_FUNCTION_FIRST_PERSON_TOGGLE }, { INPUT_FUNCTION_EVA_OBJECTIVES_SCREEN, IDS_FUNCTION_EVA_OBJECTIVES_SCREEN }, { INPUT_FUNCTION_EVA_MAP_SCREEN, IDS_FUNCTION_EVA_MAP_SCREEN }, { INPUT_FUNCTION_BEGIN_PUBLIC_MESSAGE, IDS_FUNCTION_BEGIN_PUBLIC_MESSAGE }, { INPUT_FUNCTION_BEGIN_TEAM_MESSAGE, IDS_FUNCTION_BEGIN_TEAM_MESSAGE }, { INPUT_FUNCTION_TEAM_INFO_TOGGLE, IDS_FUNCTION_TEAM_INFO_TOGGLE }, { INPUT_FUNCTION_BATTLE_INFO_TOGGLE, IDS_FUNCTION_BATTLE_INFO_TOGGLE } }; const int INPUT_NAME_COUNT = sizeof (FUNCTION_NAMES) / sizeof (FUNCTION_NAMES[0]); //////////////////////////////////////////////////////////////// // // ControlsListTabClass // //////////////////////////////////////////////////////////////// ControlsListTabClass::ControlsListTabClass (int res_id) : PendingCtrlID (0), PendingFunctionID (0), PendingDIK_ID (0), PendingOldFunctionID (0), ChildDialogClass (res_id) { return ; } //////////////////////////////////////////////////////////////// // // On_Init_Dialog // //////////////////////////////////////////////////////////////// void ControlsListTabClass::On_Init_Dialog (void) { Load_Key_Mappings (); ChildDialogClass::On_Init_Dialog (); return ; } //////////////////////////////////////////////////////////////// // // Find_Function_By_Key // //////////////////////////////////////////////////////////////// int ControlsListTabClass::Find_Function_By_Key (int curr_function_id, int dik_id) { int retval = -1; // // Test this key against all the other re-mappable keys // for (int index = 0; index < INPUT_NAME_COUNT; index ++) { int fn_id = FUNCTION_NAMES[index].function_id; // // Is this the function we're looking for? // if ( Input::Get_Primary_Key_For_Function (fn_id) == dik_id || Input::Get_Secondary_Key_For_Function (fn_id) == dik_id) { // // Note: We allow the sniper zoom in/out keys to be remapped // to other functions. (But not to each other) // if ( (fn_id != INPUT_FUNCTION_ZOOM_IN && fn_id != INPUT_FUNCTION_ZOOM_OUT) && (curr_function_id != INPUT_FUNCTION_ZOOM_IN && curr_function_id != INPUT_FUNCTION_ZOOM_OUT)) { retval = fn_id; break; } else if ( (fn_id != curr_function_id) && (fn_id == INPUT_FUNCTION_ZOOM_IN || fn_id == INPUT_FUNCTION_ZOOM_OUT) && (curr_function_id == INPUT_FUNCTION_ZOOM_IN || curr_function_id == INPUT_FUNCTION_ZOOM_OUT)) { retval = fn_id; break; } } } return retval; } //////////////////////////////////////////////////////////////// // // On_InputCtrl_Get_Key_Info // //////////////////////////////////////////////////////////////// bool ControlsListTabClass::On_InputCtrl_Get_Key_Info ( InputCtrlClass * viewer_ctrl, int ctrl_id, int vkey_id, WideStringClass & key_name, int * game_key_id ) { bool retval = false; // // First, determine what DIK key this corresponds to // int dik_id = 0; switch (vkey_id) { case 0: dik_id = 0; break; case VK_LBUTTON: dik_id = DirectInput::BUTTON_MOUSE_LEFT; break; case VK_RBUTTON: dik_id = DirectInput::BUTTON_MOUSE_RIGHT; break; case VK_MBUTTON: dik_id = DirectInput::BUTTON_MOUSE_CENTER; break; case VK_MOUSEWHEEL_UP: dik_id = Input::SLIDER_MOUSE_WHEEL_FORWARD; break; case VK_MOUSEWHEEL_DOWN: dik_id = Input::SLIDER_MOUSE_WHEEL_BACKWARD; break; default: { // // Get the last key pressed from direct input // dik_id = DirectInput::Get_Last_Key_Pressed (); break; } } // // Return the DIK key ID to the caller // (*game_key_id) = dik_id; if (dik_id != 0) { Input::Get_Translated_Key_Name (dik_id, key_name); } // // Get the function ID associated with this control // int function_id = int(viewer_ctrl->Get_User_Data ()) - 1; if (function_id >= 0) { // // Do nothing for these keys.... // if ( dik_id != DIK_APPS && dik_id != DIK_WIN && dik_id != DIK_LWIN && dik_id != DIK_RWIN && dik_id != DIK_LCONTROL && dik_id != DIK_RCONTROL && dik_id != DIK_LALT && dik_id != DIK_RALT && dik_id != DIK_ALT && dik_id != DIK_DELETE && dik_id != 0) { retval = true; // // Is this key already mapped to a function? // int old_function_id = Find_Function_By_Key (function_id, dik_id); if (old_function_id == -1 || old_function_id == function_id) { // // The key is unmapped, so allow the remap // Remap_Key (ctrl_id, function_id, dik_id); } else { // // Check to see if its OK to remap this key... // PendingCtrlID = ctrl_id; PendingFunctionID = function_id; PendingDIK_ID = dik_id; PendingOldFunctionID = old_function_id; Prompt_User (); } } else if (dik_id == DIK_DELETE) { retval = true; // // Clear the mapping. // Remap_Key (ctrl_id, function_id, 0); key_name = L""; (*game_key_id) = 0; } } return retval; } //////////////////////////////////////////////////////////////// // // Prompt_User // //////////////////////////////////////////////////////////////// void ControlsListTabClass::Prompt_User (void) { // // Get the name of the key we're remapping... // WideStringClass key_name; Input::Get_Translated_Key_Name (PendingDIK_ID, key_name); // // Get the name of the function we're remapping // WideStringClass function_name = Get_Function_Name (PendingOldFunctionID); WideStringClass message (0, true); message.Format (TRANSLATE (IDS_CONTROL_REMAP_WARNING), (const WCHAR *)key_name, (const WCHAR *)function_name); // // Display the message box // DlgMsgBox::DoDialog (0, message, DlgMsgBox::YesNo, this); return ; } //////////////////////////////////////////////////////////////// // // Remap_Key // //////////////////////////////////////////////////////////////// void ControlsListTabClass::Remap_Key (int ctrl_id, int function_id, int dik_id) { // // Determine if this is a primary or secondary key mapping // if (PrimaryCtrlIDList.ID (ctrl_id) != -1) { // // Modify the key mapping // Input::Set_Primary_Key_For_Function (function_id, dik_id); } else if (SecondaryCtrlIDList.ID (ctrl_id) != -1) { // // Modify the key mapping // Input::Set_Secondary_Key_For_Function (function_id, dik_id); } return ; } //////////////////////////////////////////////////////////////// // // Load_Key_Mappings // //////////////////////////////////////////////////////////////// void ControlsListTabClass::Load_Key_Mappings (void) { for (int index = 0; index < FunctionIDList.Count (); index ++) { // // Get the dialog control that will represent this input // InputCtrlClass *input_ctrl = (InputCtrlClass *)Get_Dlg_Item (PrimaryCtrlIDList[index]); if (input_ctrl != NULL) { WideStringClass key_name; // // Get the primary input for this function // int dik_id = Input::Get_Primary_Key_For_Function (FunctionIDList[index]); if (dik_id >= 0) { Input::Get_Translated_Key_Name (dik_id, key_name); } // // Set the key assigment for this input // input_ctrl->Set_Key_Assignment (dik_id, key_name); input_ctrl->Set_User_Data (FunctionIDList[index] + 1); } // // Get the dialog control that will represent this input // input_ctrl = (InputCtrlClass *)Get_Dlg_Item (SecondaryCtrlIDList[index]); if (input_ctrl != NULL) { WideStringClass key_name; // // Get the secondary input for this function // int dik_id = Input::Get_Secondary_Key_For_Function (FunctionIDList[index]); if (dik_id >= 0) { Input::Get_Translated_Key_Name (dik_id, key_name); } // // Set the key assigment for this input // input_ctrl->Set_Key_Assignment (dik_id, key_name); input_ctrl->Set_User_Data (FunctionIDList[index] + 1); } } return ; } //////////////////////////////////////////////////////////////// // // On_Reload // //////////////////////////////////////////////////////////////// void ControlsListTabClass::On_Reload (void) { Load_Key_Mappings (); return ; } //////////////////////////////////////////////////////////////// // // Add_Function // //////////////////////////////////////////////////////////////// void ControlsListTabClass::Add_Function (int function_id, int pri_ctrl_id, int sec_ctrl_id) { FunctionIDList.Add (function_id); PrimaryCtrlIDList.Add (pri_ctrl_id); SecondaryCtrlIDList.Add (sec_ctrl_id); return ; } //////////////////////////////////////////////////////////////// // // HandleNotification // //////////////////////////////////////////////////////////////// void ControlsListTabClass::HandleNotification (DlgMsgBoxEvent &event) { if (event.Event () == DlgMsgBoxEvent::Yes) { // // Clear all functions that currently use this key // bool clear_zoom = (PendingFunctionID == INPUT_FUNCTION_ZOOM_IN) || (PendingFunctionID == INPUT_FUNCTION_ZOOM_OUT); Clear_Key (PendingDIK_ID, clear_zoom); // // Proceed with the re-mapping // Remap_Key (PendingCtrlID, PendingFunctionID, PendingDIK_ID); // // Now, update all the controls on the dialog // DialogBaseClass *parent_dlg = Get_Parent_Dialog (); if (parent_dlg != NULL) { ((ControlsMenuClass *)parent_dlg)->Reload (); } // // Return focus to the input ctrl // Get_Dlg_Item (PendingCtrlID)->Set_Focus (); } else if (event.Event () == DlgMsgBoxEvent::No) { // // Reload the mappings on this page // Load_Key_Mappings (); Get_Dlg_Item (PendingCtrlID)->Set_Focus (); PendingCtrlID = 0; PendingFunctionID = 0; PendingDIK_ID = 0; PendingOldFunctionID = 0; } return ; } //////////////////////////////////////////////////////////////// // // Clear_Key // //////////////////////////////////////////////////////////////// void ControlsListTabClass::Clear_Key (int dik_id, bool clear_zoom) { // // First, clear all functions that use this key as a primary key // int function_id = Input::Find_First_Function_By_Primary_Key (dik_id); while (function_id != -1) { if ( clear_zoom || (function_id != INPUT_FUNCTION_ZOOM_IN && function_id != INPUT_FUNCTION_ZOOM_OUT)) { Input::Set_Primary_Key_For_Function (function_id, 0); } function_id = Input::Find_Next_Function_By_Primary_Key (function_id, dik_id); } // // Now, clear all functions that use this key as a secondary key // function_id = Input::Find_First_Function_By_Secondary_Key (dik_id); while (function_id != -1) { if ( clear_zoom || (function_id != INPUT_FUNCTION_ZOOM_IN && function_id != INPUT_FUNCTION_ZOOM_OUT)) { Input::Set_Secondary_Key_For_Function (function_id, 0); } function_id = Input::Find_Next_Function_By_Secondary_Key (function_id, dik_id); } return ; } //////////////////////////////////////////////////////////////// // // Get_Function_Name // //////////////////////////////////////////////////////////////// const WCHAR * ControlsListTabClass::Get_Function_Name (int function_id) { const WCHAR *retval = NULL; for (int index = 0; index < INPUT_NAME_COUNT; index ++) { // // Is this the function we're looking for? // if (FUNCTION_NAMES[index].function_id == function_id) { retval = TRANSLATE (FUNCTION_NAMES[index].name_id); break; } } return retval; }