dlgcontrolslisttab.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/commando/dlgcontrolslisttab.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 1/17/02 11:22a $*
  29. * *
  30. * $Revision:: 11 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "dlgcontrolslisttab.h"
  36. #include "inputctrl.h"
  37. #include "input.h"
  38. #include "dlgcontrols.h"
  39. #include "string_ids.h"
  40. #include "translatedb.h"
  41. #define DIRECTINPUT_VERSION 0x0800
  42. #include <dinput.h>
  43. #include "directinput.h"
  44. ////////////////////////////////////////////////////////////////
  45. // Local constants
  46. ////////////////////////////////////////////////////////////////
  47. typedef struct
  48. {
  49. int function_id;
  50. int name_id;
  51. } INPUT_FUNCTION_NAME;
  52. const INPUT_FUNCTION_NAME FUNCTION_NAMES[] =
  53. {
  54. { INPUT_FUNCTION_MOVE_FORWARD, IDS_FUNCTION_MOVE_FORWARD },
  55. { INPUT_FUNCTION_MOVE_BACKWARD, IDS_FUNCTION_MOVE_BACKWARD },
  56. { INPUT_FUNCTION_MOVE_LEFT, IDS_FUNCTION_MOVE_LEFT },
  57. { INPUT_FUNCTION_MOVE_RIGHT, IDS_FUNCTION_MOVE_RIGHT },
  58. { INPUT_FUNCTION_TURN_LEFT, IDS_FUNCTION_TURN_LEFT },
  59. { INPUT_FUNCTION_TURN_RIGHT, IDS_FUNCTION_TURN_RIGHT },
  60. { INPUT_FUNCTION_WALK_MODE, IDS_FUNCTION_WALK_MODE },
  61. { INPUT_FUNCTION_JUMP, IDS_FUNCTION_JUMP },
  62. { INPUT_FUNCTION_CROUCH, IDS_FUNCTION_CROUCH },
  63. { INPUT_FUNCTION_ACTION, IDS_FUNCTION_ACTION },
  64. { INPUT_FUNCTION_TURN_AROUND, IDS_FUNCTION_TURN_AROUND },
  65. { INPUT_FUNCTION_FIRE_WEAPON_PRIMARY, IDS_FUNCTION_FIRE_WEAPON_PRIMARY },
  66. { INPUT_FUNCTION_FIRE_WEAPON_SECONDARY, IDS_FUNCTION_FIRE_WEAPON_SECONDARY },
  67. { INPUT_FUNCTION_PREV_WEAPON, IDS_FUNCTION_PREV_WEAPON },
  68. { INPUT_FUNCTION_NEXT_WEAPON, IDS_FUNCTION_NEXT_WEAPON },
  69. { INPUT_FUNCTION_RELOAD_WEAPON, IDS_FUNCTION_RELOAD_WEAPON },
  70. { INPUT_FUNCTION_ZOOM_IN, IDS_FUNCTION_ZOOM_IN },
  71. { INPUT_FUNCTION_ZOOM_OUT, IDS_FUNCTION_ZOOM_OUT },
  72. { INPUT_FUNCTION_SELECT_WEAPON_1, IDS_FUNCTION_SELECT_WEAPON_1 },
  73. { INPUT_FUNCTION_SELECT_WEAPON_2, IDS_FUNCTION_SELECT_WEAPON_2 },
  74. { INPUT_FUNCTION_SELECT_WEAPON_3, IDS_FUNCTION_SELECT_WEAPON_3 },
  75. { INPUT_FUNCTION_SELECT_WEAPON_4, IDS_FUNCTION_SELECT_WEAPON_4 },
  76. { INPUT_FUNCTION_SELECT_WEAPON_5, IDS_FUNCTION_SELECT_WEAPON_5 },
  77. { INPUT_FUNCTION_SELECT_WEAPON_6, IDS_FUNCTION_SELECT_WEAPON_6 },
  78. { INPUT_FUNCTION_SELECT_WEAPON_7, IDS_FUNCTION_SELECT_WEAPON_7 },
  79. { INPUT_FUNCTION_SELECT_WEAPON_8, IDS_FUNCTION_SELECT_WEAPON_8 },
  80. { INPUT_FUNCTION_SELECT_WEAPON_9, IDS_FUNCTION_SELECT_WEAPON_9 },
  81. { INPUT_FUNCTION_SELECT_WEAPON_0, IDS_FUNCTION_SELECT_WEAPON_0 },
  82. { INPUT_FUNCTION_CURSOR_TARGETING, IDS_FUNCTION_CURSOR_TARGETING },
  83. { INPUT_FUNCTION_FIRST_PERSON_TOGGLE, IDS_FUNCTION_FIRST_PERSON_TOGGLE },
  84. { INPUT_FUNCTION_EVA_OBJECTIVES_SCREEN, IDS_FUNCTION_EVA_OBJECTIVES_SCREEN },
  85. { INPUT_FUNCTION_EVA_MAP_SCREEN, IDS_FUNCTION_EVA_MAP_SCREEN },
  86. { INPUT_FUNCTION_BEGIN_PUBLIC_MESSAGE, IDS_FUNCTION_BEGIN_PUBLIC_MESSAGE },
  87. { INPUT_FUNCTION_BEGIN_TEAM_MESSAGE, IDS_FUNCTION_BEGIN_TEAM_MESSAGE },
  88. { INPUT_FUNCTION_TEAM_INFO_TOGGLE, IDS_FUNCTION_TEAM_INFO_TOGGLE },
  89. { INPUT_FUNCTION_BATTLE_INFO_TOGGLE, IDS_FUNCTION_BATTLE_INFO_TOGGLE }
  90. };
  91. const int INPUT_NAME_COUNT = sizeof (FUNCTION_NAMES) / sizeof (FUNCTION_NAMES[0]);
  92. ////////////////////////////////////////////////////////////////
  93. //
  94. // ControlsListTabClass
  95. //
  96. ////////////////////////////////////////////////////////////////
  97. ControlsListTabClass::ControlsListTabClass (int res_id) :
  98. PendingCtrlID (0),
  99. PendingFunctionID (0),
  100. PendingDIK_ID (0),
  101. PendingOldFunctionID (0),
  102. ChildDialogClass (res_id)
  103. {
  104. return ;
  105. }
  106. ////////////////////////////////////////////////////////////////
  107. //
  108. // On_Init_Dialog
  109. //
  110. ////////////////////////////////////////////////////////////////
  111. void
  112. ControlsListTabClass::On_Init_Dialog (void)
  113. {
  114. Load_Key_Mappings ();
  115. ChildDialogClass::On_Init_Dialog ();
  116. return ;
  117. }
  118. ////////////////////////////////////////////////////////////////
  119. //
  120. // Find_Function_By_Key
  121. //
  122. ////////////////////////////////////////////////////////////////
  123. int
  124. ControlsListTabClass::Find_Function_By_Key (int curr_function_id, int dik_id)
  125. {
  126. int retval = -1;
  127. //
  128. // Test this key against all the other re-mappable keys
  129. //
  130. for (int index = 0; index < INPUT_NAME_COUNT; index ++) {
  131. int fn_id = FUNCTION_NAMES[index].function_id;
  132. //
  133. // Is this the function we're looking for?
  134. //
  135. if ( Input::Get_Primary_Key_For_Function (fn_id) == dik_id ||
  136. Input::Get_Secondary_Key_For_Function (fn_id) == dik_id)
  137. {
  138. //
  139. // Note: We allow the sniper zoom in/out keys to be remapped
  140. // to other functions. (But not to each other)
  141. //
  142. if ( (fn_id != INPUT_FUNCTION_ZOOM_IN && fn_id != INPUT_FUNCTION_ZOOM_OUT) &&
  143. (curr_function_id != INPUT_FUNCTION_ZOOM_IN && curr_function_id != INPUT_FUNCTION_ZOOM_OUT))
  144. {
  145. retval = fn_id;
  146. break;
  147. } else if ( (fn_id != curr_function_id) &&
  148. (fn_id == INPUT_FUNCTION_ZOOM_IN || fn_id == INPUT_FUNCTION_ZOOM_OUT) &&
  149. (curr_function_id == INPUT_FUNCTION_ZOOM_IN || curr_function_id == INPUT_FUNCTION_ZOOM_OUT))
  150. {
  151. retval = fn_id;
  152. break;
  153. }
  154. }
  155. }
  156. return retval;
  157. }
  158. ////////////////////////////////////////////////////////////////
  159. //
  160. // On_InputCtrl_Get_Key_Info
  161. //
  162. ////////////////////////////////////////////////////////////////
  163. bool
  164. ControlsListTabClass::On_InputCtrl_Get_Key_Info
  165. (
  166. InputCtrlClass * viewer_ctrl,
  167. int ctrl_id,
  168. int vkey_id,
  169. WideStringClass & key_name,
  170. int * game_key_id
  171. )
  172. {
  173. bool retval = false;
  174. //
  175. // First, determine what DIK key this corresponds to
  176. //
  177. int dik_id = 0;
  178. switch (vkey_id)
  179. {
  180. case 0:
  181. dik_id = 0;
  182. break;
  183. case VK_LBUTTON:
  184. dik_id = DirectInput::BUTTON_MOUSE_LEFT;
  185. break;
  186. case VK_RBUTTON:
  187. dik_id = DirectInput::BUTTON_MOUSE_RIGHT;
  188. break;
  189. case VK_MBUTTON:
  190. dik_id = DirectInput::BUTTON_MOUSE_CENTER;
  191. break;
  192. case VK_MOUSEWHEEL_UP:
  193. dik_id = Input::SLIDER_MOUSE_WHEEL_FORWARD;
  194. break;
  195. case VK_MOUSEWHEEL_DOWN:
  196. dik_id = Input::SLIDER_MOUSE_WHEEL_BACKWARD;
  197. break;
  198. default:
  199. {
  200. //
  201. // Get the last key pressed from direct input
  202. //
  203. dik_id = DirectInput::Get_Last_Key_Pressed ();
  204. break;
  205. }
  206. }
  207. //
  208. // Return the DIK key ID to the caller
  209. //
  210. (*game_key_id) = dik_id;
  211. if (dik_id != 0) {
  212. Input::Get_Translated_Key_Name (dik_id, key_name);
  213. }
  214. //
  215. // Get the function ID associated with this control
  216. //
  217. int function_id = int(viewer_ctrl->Get_User_Data ()) - 1;
  218. if (function_id >= 0) {
  219. //
  220. // Do nothing for these keys....
  221. //
  222. if ( dik_id != DIK_APPS && dik_id != DIK_WIN &&
  223. dik_id != DIK_LWIN && dik_id != DIK_RWIN &&
  224. dik_id != DIK_LCONTROL && dik_id != DIK_RCONTROL &&
  225. dik_id != DIK_LALT && dik_id != DIK_RALT && dik_id != DIK_ALT &&
  226. dik_id != DIK_DELETE && dik_id != 0)
  227. {
  228. retval = true;
  229. //
  230. // Is this key already mapped to a function?
  231. //
  232. int old_function_id = Find_Function_By_Key (function_id, dik_id);
  233. if (old_function_id == -1 || old_function_id == function_id) {
  234. //
  235. // The key is unmapped, so allow the remap
  236. //
  237. Remap_Key (ctrl_id, function_id, dik_id);
  238. } else {
  239. //
  240. // Check to see if its OK to remap this key...
  241. //
  242. PendingCtrlID = ctrl_id;
  243. PendingFunctionID = function_id;
  244. PendingDIK_ID = dik_id;
  245. PendingOldFunctionID = old_function_id;
  246. Prompt_User ();
  247. }
  248. } else if (dik_id == DIK_DELETE) {
  249. retval = true;
  250. //
  251. // Clear the mapping.
  252. //
  253. Remap_Key (ctrl_id, function_id, 0);
  254. key_name = L"";
  255. (*game_key_id) = 0;
  256. }
  257. }
  258. return retval;
  259. }
  260. ////////////////////////////////////////////////////////////////
  261. //
  262. // Prompt_User
  263. //
  264. ////////////////////////////////////////////////////////////////
  265. void
  266. ControlsListTabClass::Prompt_User (void)
  267. {
  268. //
  269. // Get the name of the key we're remapping...
  270. //
  271. WideStringClass key_name;
  272. Input::Get_Translated_Key_Name (PendingDIK_ID, key_name);
  273. //
  274. // Get the name of the function we're remapping
  275. //
  276. WideStringClass function_name = Get_Function_Name (PendingOldFunctionID);
  277. WideStringClass message (0, true);
  278. message.Format (TRANSLATE (IDS_CONTROL_REMAP_WARNING),
  279. (const WCHAR *)key_name, (const WCHAR *)function_name);
  280. //
  281. // Display the message box
  282. //
  283. DlgMsgBox::DoDialog (0, message, DlgMsgBox::YesNo, this);
  284. return ;
  285. }
  286. ////////////////////////////////////////////////////////////////
  287. //
  288. // Remap_Key
  289. //
  290. ////////////////////////////////////////////////////////////////
  291. void
  292. ControlsListTabClass::Remap_Key (int ctrl_id, int function_id, int dik_id)
  293. {
  294. //
  295. // Determine if this is a primary or secondary key mapping
  296. //
  297. if (PrimaryCtrlIDList.ID (ctrl_id) != -1) {
  298. //
  299. // Modify the key mapping
  300. //
  301. Input::Set_Primary_Key_For_Function (function_id, dik_id);
  302. } else if (SecondaryCtrlIDList.ID (ctrl_id) != -1) {
  303. //
  304. // Modify the key mapping
  305. //
  306. Input::Set_Secondary_Key_For_Function (function_id, dik_id);
  307. }
  308. return ;
  309. }
  310. ////////////////////////////////////////////////////////////////
  311. //
  312. // Load_Key_Mappings
  313. //
  314. ////////////////////////////////////////////////////////////////
  315. void
  316. ControlsListTabClass::Load_Key_Mappings (void)
  317. {
  318. for (int index = 0; index < FunctionIDList.Count (); index ++) {
  319. //
  320. // Get the dialog control that will represent this input
  321. //
  322. InputCtrlClass *input_ctrl = (InputCtrlClass *)Get_Dlg_Item (PrimaryCtrlIDList[index]);
  323. if (input_ctrl != NULL) {
  324. WideStringClass key_name;
  325. //
  326. // Get the primary input for this function
  327. //
  328. int dik_id = Input::Get_Primary_Key_For_Function (FunctionIDList[index]);
  329. if (dik_id >= 0) {
  330. Input::Get_Translated_Key_Name (dik_id, key_name);
  331. }
  332. //
  333. // Set the key assigment for this input
  334. //
  335. input_ctrl->Set_Key_Assignment (dik_id, key_name);
  336. input_ctrl->Set_User_Data (FunctionIDList[index] + 1);
  337. }
  338. //
  339. // Get the dialog control that will represent this input
  340. //
  341. input_ctrl = (InputCtrlClass *)Get_Dlg_Item (SecondaryCtrlIDList[index]);
  342. if (input_ctrl != NULL) {
  343. WideStringClass key_name;
  344. //
  345. // Get the secondary input for this function
  346. //
  347. int dik_id = Input::Get_Secondary_Key_For_Function (FunctionIDList[index]);
  348. if (dik_id >= 0) {
  349. Input::Get_Translated_Key_Name (dik_id, key_name);
  350. }
  351. //
  352. // Set the key assigment for this input
  353. //
  354. input_ctrl->Set_Key_Assignment (dik_id, key_name);
  355. input_ctrl->Set_User_Data (FunctionIDList[index] + 1);
  356. }
  357. }
  358. return ;
  359. }
  360. ////////////////////////////////////////////////////////////////
  361. //
  362. // On_Reload
  363. //
  364. ////////////////////////////////////////////////////////////////
  365. void
  366. ControlsListTabClass::On_Reload (void)
  367. {
  368. Load_Key_Mappings ();
  369. return ;
  370. }
  371. ////////////////////////////////////////////////////////////////
  372. //
  373. // Add_Function
  374. //
  375. ////////////////////////////////////////////////////////////////
  376. void
  377. ControlsListTabClass::Add_Function (int function_id, int pri_ctrl_id, int sec_ctrl_id)
  378. {
  379. FunctionIDList.Add (function_id);
  380. PrimaryCtrlIDList.Add (pri_ctrl_id);
  381. SecondaryCtrlIDList.Add (sec_ctrl_id);
  382. return ;
  383. }
  384. ////////////////////////////////////////////////////////////////
  385. //
  386. // HandleNotification
  387. //
  388. ////////////////////////////////////////////////////////////////
  389. void
  390. ControlsListTabClass::HandleNotification (DlgMsgBoxEvent &event)
  391. {
  392. if (event.Event () == DlgMsgBoxEvent::Yes) {
  393. //
  394. // Clear all functions that currently use this key
  395. //
  396. bool clear_zoom = (PendingFunctionID == INPUT_FUNCTION_ZOOM_IN) || (PendingFunctionID == INPUT_FUNCTION_ZOOM_OUT);
  397. Clear_Key (PendingDIK_ID, clear_zoom);
  398. //
  399. // Proceed with the re-mapping
  400. //
  401. Remap_Key (PendingCtrlID, PendingFunctionID, PendingDIK_ID);
  402. //
  403. // Now, update all the controls on the dialog
  404. //
  405. DialogBaseClass *parent_dlg = Get_Parent_Dialog ();
  406. if (parent_dlg != NULL) {
  407. ((ControlsMenuClass *)parent_dlg)->Reload ();
  408. }
  409. //
  410. // Return focus to the input ctrl
  411. //
  412. Get_Dlg_Item (PendingCtrlID)->Set_Focus ();
  413. } else if (event.Event () == DlgMsgBoxEvent::No) {
  414. //
  415. // Reload the mappings on this page
  416. //
  417. Load_Key_Mappings ();
  418. Get_Dlg_Item (PendingCtrlID)->Set_Focus ();
  419. PendingCtrlID = 0;
  420. PendingFunctionID = 0;
  421. PendingDIK_ID = 0;
  422. PendingOldFunctionID = 0;
  423. }
  424. return ;
  425. }
  426. ////////////////////////////////////////////////////////////////
  427. //
  428. // Clear_Key
  429. //
  430. ////////////////////////////////////////////////////////////////
  431. void
  432. ControlsListTabClass::Clear_Key (int dik_id, bool clear_zoom)
  433. {
  434. //
  435. // First, clear all functions that use this key as a primary key
  436. //
  437. int function_id = Input::Find_First_Function_By_Primary_Key (dik_id);
  438. while (function_id != -1) {
  439. if ( clear_zoom ||
  440. (function_id != INPUT_FUNCTION_ZOOM_IN &&
  441. function_id != INPUT_FUNCTION_ZOOM_OUT))
  442. {
  443. Input::Set_Primary_Key_For_Function (function_id, 0);
  444. }
  445. function_id = Input::Find_Next_Function_By_Primary_Key (function_id, dik_id);
  446. }
  447. //
  448. // Now, clear all functions that use this key as a secondary key
  449. //
  450. function_id = Input::Find_First_Function_By_Secondary_Key (dik_id);
  451. while (function_id != -1) {
  452. if ( clear_zoom ||
  453. (function_id != INPUT_FUNCTION_ZOOM_IN &&
  454. function_id != INPUT_FUNCTION_ZOOM_OUT))
  455. {
  456. Input::Set_Secondary_Key_For_Function (function_id, 0);
  457. }
  458. function_id = Input::Find_Next_Function_By_Secondary_Key (function_id, dik_id);
  459. }
  460. return ;
  461. }
  462. ////////////////////////////////////////////////////////////////
  463. //
  464. // Get_Function_Name
  465. //
  466. ////////////////////////////////////////////////////////////////
  467. const WCHAR *
  468. ControlsListTabClass::Get_Function_Name (int function_id)
  469. {
  470. const WCHAR *retval = NULL;
  471. for (int index = 0; index < INPUT_NAME_COUNT; index ++) {
  472. //
  473. // Is this the function we're looking for?
  474. //
  475. if (FUNCTION_NAMES[index].function_id == function_id) {
  476. retval = TRANSLATE (FUNCTION_NAMES[index].name_id);
  477. break;
  478. }
  479. }
  480. return retval;
  481. }