564 lines
16 KiB
C++
564 lines
16 KiB
C++
/*
|
|
** 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** 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 <dinput.h>
|
|
#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;
|
|
}
|
|
|