Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // BINDINGS.CPP
  4. //
  5. // Keyboard Shortcuts
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. #define ID_BINDINGS_LISTVIEW 100
  9. // column id
  10. #define ID_BIND_KEYCODE 0
  11. #define ID_BIND_MENUNAME 1
  12. #define ID_BIND_COMMAND 2
  13. typedef struct
  14. { const CHAR* name;
  15. int width;
  16. int subItemIndex;
  17. } label_t;
  18. typedef struct
  19. {
  20. int keyCode;
  21. const char *pKeyString;
  22. char *pMenuName;
  23. char *pCommandString;
  24. } bind_t;
  25. // {VK_F1, "F1", "WireFrame", "incrementvar mat_wireframe 0 2 1"},
  26. // {VK_F2, "F2", "FullBright", "incrementvar mat_fullbright 0 2 1"},
  27. // {VK_F3, "F3", "Impulse 101", "impulse 101"},
  28. // {VK_F4, "F4", "Screenshot", "*screenshot"},
  29. bind_t g_bindings[MAX_BINDINGS] =
  30. {
  31. {VK_F1, "F1", NULL, NULL},
  32. {VK_F2, "F2", NULL, NULL},
  33. {VK_F3, "F3", NULL, NULL},
  34. {VK_F4, "F4", NULL, NULL},
  35. {VK_F5, "F5", NULL, NULL},
  36. {VK_F6, "F6", NULL, NULL},
  37. {VK_F7, "F7", NULL, NULL},
  38. {VK_F8, "F8", NULL, NULL},
  39. {VK_F9, "F9", NULL, NULL},
  40. {VK_F10, "F10", NULL, NULL},
  41. {VK_F11, "F11", NULL, NULL},
  42. {VK_F12, "F12", NULL, NULL},
  43. };
  44. label_t g_bindings_labels[] =
  45. {
  46. {"Key", 80, ID_BIND_KEYCODE},
  47. {"Menu Name", 150, ID_BIND_MENUNAME},
  48. {"Command", 400, ID_BIND_COMMAND},
  49. };
  50. HWND g_bindings_hWnd;
  51. HWND g_bindings_hWndListView;
  52. RECT g_bindings_windowRect;
  53. char g_bindingsModify_menuName[256];
  54. char g_bindingsModify_command[256];
  55. char g_bindingsModify_keyCode[256];
  56. //-----------------------------------------------------------------------------
  57. // Bindings_ModifyEntry
  58. //
  59. //-----------------------------------------------------------------------------
  60. void Bindings_ModifyEntry( int i, const char *pMenuName, const char *pCommandString )
  61. {
  62. if ( g_bindings[i].pMenuName && g_bindings[i].pMenuName[0] )
  63. Sys_Free( g_bindings[i].pMenuName );
  64. g_bindings[i].pMenuName = Sys_CopyString( pMenuName );
  65. if ( g_bindings[i].pCommandString && g_bindings[i].pCommandString[0] )
  66. Sys_Free( g_bindings[i].pCommandString );
  67. g_bindings[i].pCommandString = Sys_CopyString( pCommandString );
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Bindings_GetSelectedItem
  71. //
  72. //-----------------------------------------------------------------------------
  73. int Bindings_GetSelectedItem()
  74. {
  75. int i;
  76. int selection = -1;
  77. int state;
  78. for ( i=0; i<MAX_BINDINGS; i++ )
  79. {
  80. state = ListView_GetItemState( g_bindings_hWndListView, i, LVIS_SELECTED );
  81. if ( state == LVIS_SELECTED )
  82. {
  83. selection = i;
  84. break;
  85. }
  86. }
  87. return selection;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Bindings_TranslateKey
  91. //
  92. //-----------------------------------------------------------------------------
  93. bool Bindings_TranslateKey( int vkKeyCode )
  94. {
  95. int i;
  96. for ( i=0; i<MAX_BINDINGS; i++ )
  97. {
  98. if ( !g_bindings[i].pCommandString || !g_bindings[i].pCommandString[0] )
  99. continue;
  100. if ( vkKeyCode == g_bindings[i].keyCode )
  101. {
  102. ProcessCommand( g_bindings[i].pCommandString );
  103. return true;
  104. }
  105. }
  106. return false;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Bindings_MenuSelection
  110. //
  111. //-----------------------------------------------------------------------------
  112. bool Bindings_MenuSelection( int wID )
  113. {
  114. int index;
  115. index = wID - IDM_BINDINGS_BIND1;
  116. if ( index < 0 || index > MAX_BINDINGS-1 )
  117. return false;
  118. // as if the key were pressed...
  119. return ( Bindings_TranslateKey( g_bindings[index].keyCode ) );
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Bindings_UpdateMenu
  123. //
  124. // Builds the dynamic menu
  125. //-----------------------------------------------------------------------------
  126. void Bindings_UpdateMenu()
  127. {
  128. HMENU hMenu;
  129. HMENU hNewMenu;
  130. MENUITEMINFO menuItemInfo;
  131. int i;
  132. int numAdded;
  133. char menuBuff[64];
  134. hMenu = GetMenu( g_hDlgMain );
  135. if ( !hMenu )
  136. return;
  137. memset( &menuItemInfo, 0, sizeof( menuItemInfo ) );
  138. menuItemInfo.cbSize = sizeof( MENUITEMINFO );
  139. numAdded = 0;
  140. hNewMenu = CreatePopupMenu();
  141. menuItemInfo.fMask = MIIM_ID|MIIM_FTYPE|MIIM_STRING;
  142. menuItemInfo.fType = MFT_STRING;
  143. for ( i=MAX_BINDINGS-1; i>=0; i-- )
  144. {
  145. if ( !g_bindings[i].pCommandString || !g_bindings[i].pCommandString[0] )
  146. continue;
  147. menuItemInfo.wID = IDM_BINDINGS_BIND1+i;
  148. sprintf( menuBuff, "%s\tF%d", g_bindings[i].pMenuName, g_bindings[i].keyCode-VK_F1+1 );
  149. menuItemInfo.dwTypeData = ( LPSTR )menuBuff;
  150. InsertMenuItem( hNewMenu, 0, true, &menuItemInfo );
  151. numAdded++;
  152. }
  153. if ( numAdded )
  154. {
  155. // add seperator
  156. menuItemInfo.fMask = MIIM_FTYPE;
  157. menuItemInfo.fType = MFT_SEPARATOR;
  158. InsertMenuItem( hNewMenu, 0, true, &menuItemInfo );
  159. }
  160. menuItemInfo.fMask = MIIM_ID|MIIM_FTYPE|MIIM_STRING;
  161. menuItemInfo.fType = MFT_STRING;
  162. menuItemInfo.wID = IDM_BINDINGS_EDIT;
  163. menuItemInfo.dwTypeData = "Edit...";
  164. InsertMenuItem( hNewMenu, 0, true, &menuItemInfo );
  165. // delete the previous menu
  166. menuItemInfo.fMask = MIIM_SUBMENU;
  167. GetMenuItemInfo( hMenu, IDM_BINDINGS, false, &menuItemInfo );
  168. if ( menuItemInfo.hSubMenu )
  169. DestroyMenu( menuItemInfo.hSubMenu );
  170. else
  171. {
  172. // add a new menu at the tail of the app menu
  173. AppendMenu( hMenu, MF_STRING, ( UINT_PTR )IDM_BINDINGS, "Bindings" );
  174. }
  175. // add the new menu to bar
  176. menuItemInfo.fMask = MIIM_SUBMENU;
  177. menuItemInfo.hSubMenu = hNewMenu;
  178. SetMenuItemInfo( hMenu, IDM_BINDINGS, false, &menuItemInfo );
  179. DrawMenuBar( g_hDlgMain );
  180. }
  181. //-----------------------------------------------------------------------------
  182. // BindingsModifyDlg_Proc
  183. //
  184. //-----------------------------------------------------------------------------
  185. BOOL CALLBACK BindingsModifyDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  186. {
  187. switch ( message )
  188. {
  189. case WM_INITDIALOG:
  190. SetDlgItemText( hWnd, IDC_MODIFYBIND_KEYCODE, g_bindingsModify_keyCode );
  191. SetDlgItemText( hWnd, IDC_MODIFYBIND_MENUNAME, g_bindingsModify_menuName );
  192. SetDlgItemText( hWnd, IDC_MODIFYBIND_COMMAND, g_bindingsModify_command );
  193. return ( TRUE );
  194. case WM_COMMAND:
  195. switch ( LOWORD( wParam ) )
  196. {
  197. case IDC_OK:
  198. GetDlgItemText( hWnd, IDC_MODIFYBIND_MENUNAME, g_bindingsModify_menuName, sizeof( g_bindingsModify_menuName ) );
  199. GetDlgItemText( hWnd, IDC_MODIFYBIND_COMMAND, g_bindingsModify_command, sizeof( g_bindingsModify_command ) );
  200. case IDCANCEL:
  201. case IDC_CANCEL:
  202. EndDialog( hWnd, wParam );
  203. return ( TRUE );
  204. }
  205. break;
  206. }
  207. return ( FALSE );
  208. }
  209. //-----------------------------------------------------------------------------
  210. // BindingsModifyDlg_Open
  211. //
  212. //-----------------------------------------------------------------------------
  213. void BindingsModifyDlg_Open( int selection )
  214. {
  215. int result;
  216. sprintf( g_bindingsModify_keyCode, "F%d", selection+1 );
  217. strcpy( g_bindingsModify_menuName, g_bindings[selection].pMenuName );
  218. strcpy( g_bindingsModify_command, g_bindings[selection].pCommandString );
  219. result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_MODIFYBIND ), g_hDlgMain, ( DLGPROC )BindingsModifyDlg_Proc );
  220. if ( LOWORD( result ) != IDC_OK )
  221. return;
  222. // accept changes and update
  223. Bindings_ModifyEntry( selection, g_bindingsModify_menuName, g_bindingsModify_command );
  224. ListView_RedrawItems( g_bindings_hWndListView, 0, MAX_BINDINGS-1 );
  225. UpdateWindow( g_bindings_hWndListView );
  226. Bindings_UpdateMenu();
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Bindings_LoadConfig
  230. //
  231. //-----------------------------------------------------------------------------
  232. void Bindings_LoadConfig()
  233. {
  234. char valueBuff[256];
  235. char keyBuff[32];
  236. char menuName[256];
  237. char commandString[256];
  238. char *ptr;
  239. char *token;
  240. int keyCode;
  241. int i;
  242. int numArgs;
  243. char buff[256];
  244. for ( i=0; i<MAX_BINDINGS; i++ )
  245. {
  246. menuName[0] = '\0';
  247. commandString[0] = '\0';
  248. sprintf( keyBuff, "bind%d", i );
  249. Sys_GetRegistryString( keyBuff, valueBuff, "", sizeof( valueBuff ) );
  250. // parse and populate valid values
  251. ptr = valueBuff;
  252. token = Sys_GetToken( &ptr, false, NULL );
  253. if ( token[0] )
  254. keyCode = atoi( token );
  255. token = Sys_GetToken( &ptr, false, NULL );
  256. if ( token[0] )
  257. strcpy( menuName, token );
  258. token = Sys_GetToken( &ptr, false, NULL );
  259. if ( token[0] )
  260. strcpy( commandString, token );
  261. Bindings_ModifyEntry( i, menuName, commandString );
  262. }
  263. Sys_GetRegistryString( "bindingsWindowRect", buff, "", sizeof( buff ) );
  264. numArgs = sscanf( buff, "%d %d %d %d", &g_bindings_windowRect.left, &g_bindings_windowRect.top, &g_bindings_windowRect.right, &g_bindings_windowRect.bottom );
  265. if ( numArgs != 4 )
  266. memset( &g_bindings_windowRect, 0, sizeof( g_bindings_windowRect ) );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Bindings_SaveConfig
  270. //
  271. //-----------------------------------------------------------------------------
  272. void Bindings_SaveConfig()
  273. {
  274. char valueBuff[256];
  275. char buff[256];
  276. char keyBuff[32];
  277. char *pMenuName;
  278. char *pCommandString;
  279. int len;
  280. int i;
  281. WINDOWPLACEMENT wp;
  282. if ( g_bindings_hWnd )
  283. {
  284. memset( &wp, 0, sizeof( wp ) );
  285. wp.length = sizeof( WINDOWPLACEMENT );
  286. GetWindowPlacement( g_bindings_hWnd, &wp );
  287. g_bindings_windowRect = wp.rcNormalPosition;
  288. sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom );
  289. Sys_SetRegistryString( "bindingsWindowRect", buff );
  290. }
  291. for ( i=0; i<MAX_BINDINGS; i++ )
  292. {
  293. sprintf( keyBuff, "bind%d", i );
  294. pMenuName = g_bindings[i].pMenuName;
  295. if ( !pMenuName )
  296. pMenuName = "";
  297. pCommandString = g_bindings[i].pCommandString;
  298. if ( !pCommandString )
  299. pCommandString = "";
  300. len = _snprintf( valueBuff, sizeof( valueBuff ), "%d \"%s\" \"%s\"", g_bindings[i].keyCode, pMenuName, pCommandString );
  301. if ( len == -1 )
  302. {
  303. // kill it
  304. valueBuff[0] = '\0';
  305. }
  306. Sys_SetRegistryString( keyBuff, valueBuff );
  307. }
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Bindings_SizeWindow
  311. //
  312. //-----------------------------------------------------------------------------
  313. void Bindings_SizeWindow( HWND hwnd, int cx, int cy )
  314. {
  315. if ( cx==0 || cy==0 )
  316. {
  317. RECT rcClient;
  318. GetClientRect( hwnd, &rcClient );
  319. cx = rcClient.right;
  320. cy = rcClient.bottom;
  321. }
  322. // position the ListView
  323. SetWindowPos( g_bindings_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER );
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Bindings_WndProc
  327. //
  328. //-----------------------------------------------------------------------------
  329. LRESULT CALLBACK Bindings_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  330. {
  331. WORD wID = LOWORD( wParam );
  332. bind_t* pBind;
  333. int selection;
  334. switch ( message )
  335. {
  336. case WM_CREATE:
  337. return 0L;
  338. case WM_DESTROY:
  339. Bindings_SaveConfig();
  340. Bindings_UpdateMenu();
  341. g_bindings_hWnd = NULL;
  342. return 0L;
  343. case WM_SIZE:
  344. Bindings_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) );
  345. return 0L;
  346. case WM_NOTIFY:
  347. switch ( ( ( LPNMHDR )lParam )->code )
  348. {
  349. case LVN_GETDISPINFO:
  350. NMLVDISPINFO* plvdi;
  351. plvdi = ( NMLVDISPINFO* )lParam;
  352. pBind = ( bind_t* )plvdi->item.lParam;
  353. switch ( plvdi->item.iSubItem )
  354. {
  355. case ID_BIND_KEYCODE:
  356. plvdi->item.pszText = ( LPSTR )pBind->pKeyString;
  357. return 0L;
  358. case ID_BIND_MENUNAME:
  359. plvdi->item.pszText = pBind->pMenuName;
  360. return 0L;
  361. case ID_BIND_COMMAND:
  362. plvdi->item.pszText = pBind->pCommandString;
  363. return 0L;
  364. default:
  365. break;
  366. }
  367. break;
  368. case NM_DBLCLK:
  369. NMITEMACTIVATE *pnmitem;
  370. pnmitem = ( LPNMITEMACTIVATE )lParam;
  371. BindingsModifyDlg_Open( pnmitem->iItem );
  372. break;
  373. }
  374. break;
  375. case WM_COMMAND:
  376. switch ( wID )
  377. {
  378. case IDM_BINDOPTIONS_MODIFY:
  379. selection = Bindings_GetSelectedItem();
  380. if ( selection >= 0 )
  381. BindingsModifyDlg_Open( selection );
  382. return 0L;
  383. case IDM_BINDOPTIONS_DELETE:
  384. selection = Bindings_GetSelectedItem();
  385. if ( selection >= 0 )
  386. {
  387. Bindings_ModifyEntry( selection, "", "" );
  388. ListView_RedrawItems( g_bindings_hWndListView, 0, MAX_BINDINGS-1 );
  389. UpdateWindow( g_bindings_hWndListView );
  390. Bindings_UpdateMenu();
  391. }
  392. return 0L;
  393. }
  394. break;
  395. }
  396. return ( DefWindowProc( hwnd, message, wParam, lParam ) );
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Bindings_Open
  400. //
  401. //-----------------------------------------------------------------------------
  402. void Bindings_Open()
  403. {
  404. RECT clientRect;
  405. HWND hWnd;
  406. int i;
  407. LVITEM lvi;
  408. if ( g_bindings_hWnd )
  409. {
  410. // only one instance
  411. if ( IsIconic( g_bindings_hWnd ) )
  412. ShowWindow( g_bindings_hWnd, SW_RESTORE );
  413. SetForegroundWindow( g_bindings_hWnd );
  414. return;
  415. }
  416. hWnd = CreateWindowEx(
  417. WS_EX_CLIENTEDGE,
  418. "BINDINGSCLASS",
  419. "Edit Bindings",
  420. WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
  421. 0,
  422. 0,
  423. 600,
  424. 300,
  425. g_hDlgMain,
  426. NULL,
  427. g_hInstance,
  428. NULL );
  429. g_bindings_hWnd = hWnd;
  430. GetClientRect( g_bindings_hWnd, &clientRect );
  431. hWnd = CreateWindow(
  432. WC_LISTVIEW,
  433. "",
  434. WS_VISIBLE|WS_CHILD|LVS_REPORT|LVS_SHOWSELALWAYS|LVS_SINGLESEL|LVS_NOSORTHEADER,
  435. 0,
  436. 0,
  437. clientRect.right-clientRect.left,
  438. clientRect.bottom-clientRect.top,
  439. g_bindings_hWnd,
  440. ( HMENU )ID_BINDINGS_LISTVIEW,
  441. g_hInstance,
  442. NULL );
  443. g_bindings_hWndListView = hWnd;
  444. // init list view columns
  445. for ( i=0; i<sizeof( g_bindings_labels )/sizeof( g_bindings_labels[0] ); i++ )
  446. {
  447. LVCOLUMN lvc;
  448. memset( &lvc, 0, sizeof( lvc ) );
  449. lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
  450. lvc.iSubItem = 0;
  451. lvc.cx = g_bindings_labels[i].width;
  452. lvc.fmt = LVCFMT_LEFT;
  453. lvc.pszText = ( LPSTR )g_bindings_labels[i].name;
  454. ListView_InsertColumn( g_bindings_hWndListView, i, &lvc );
  455. }
  456. ListView_SetBkColor( g_bindings_hWndListView, g_backgroundColor );
  457. ListView_SetTextBkColor( g_bindings_hWndListView, g_backgroundColor );
  458. DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP;
  459. ListView_SetExtendedListViewStyleEx( g_bindings_hWndListView, style, style );
  460. // populate list view
  461. for ( i=0; i<MAX_BINDINGS; i++ )
  462. {
  463. int itemCount = ListView_GetItemCount( g_bindings_hWndListView );
  464. // setup and insert at end of list
  465. memset( &lvi, 0, sizeof( lvi ) );
  466. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  467. lvi.iItem = itemCount;
  468. lvi.iSubItem = 0;
  469. lvi.state = 0;
  470. lvi.stateMask = 0;
  471. lvi.pszText = LPSTR_TEXTCALLBACK;
  472. lvi.lParam = ( LPARAM )&g_bindings[i];
  473. ListView_InsertItem( g_bindings_hWndListView, &lvi );
  474. }
  475. // set the first item selected
  476. ListView_SetItemState( g_bindings_hWndListView, 0, LVIS_SELECTED, LVIS_SELECTED );
  477. SetFocus( g_bindings_hWndListView );
  478. if ( g_bindings_windowRect.right && g_bindings_windowRect.bottom )
  479. MoveWindow( g_bindings_hWnd, g_bindings_windowRect.left, g_bindings_windowRect.top, g_bindings_windowRect.right-g_bindings_windowRect.left, g_bindings_windowRect.bottom-g_bindings_windowRect.top, FALSE );
  480. ShowWindow( g_bindings_hWnd, SHOW_OPENWINDOW );
  481. }
  482. //-----------------------------------------------------------------------------
  483. // Bindings_Init
  484. //
  485. //-----------------------------------------------------------------------------
  486. bool Bindings_Init()
  487. {
  488. // set up our window class
  489. WNDCLASS wndclass;
  490. memset( &wndclass, 0, sizeof( wndclass ) );
  491. wndclass.style = 0;
  492. wndclass.lpfnWndProc = Bindings_WndProc;
  493. wndclass.cbClsExtra = 0;
  494. wndclass.cbWndExtra = 0;
  495. wndclass.hInstance = g_hInstance;
  496. wndclass.hIcon = g_hIcons[ICON_APPLICATION];
  497. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  498. wndclass.hbrBackground = g_hBackgroundBrush;
  499. wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_BINDOPTIONS );
  500. wndclass.lpszClassName = "BINDINGSCLASS";
  501. if ( !RegisterClass( &wndclass ) )
  502. return false;
  503. Bindings_LoadConfig();
  504. Bindings_UpdateMenu();
  505. return true;
  506. }