win_wndproc.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "win_local.h"
  23. #include "../../renderer/tr_local.h"
  24. #ifndef USE_SDL
  25. LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  26. static bool s_alttab_disabled;
  27. static void WIN_DisableAltTab( void ) {
  28. if ( s_alttab_disabled || win32.win_allowAltTab.GetBool() ) {
  29. return;
  30. }
  31. if ( !idStr::Icmp( cvarSystem->GetCVarString( "sys_arch" ), "winnt" ) ) {
  32. RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
  33. } else {
  34. BOOL old;
  35. SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
  36. }
  37. s_alttab_disabled = true;
  38. }
  39. static void WIN_EnableAltTab( void ) {
  40. if ( !s_alttab_disabled || win32.win_allowAltTab.GetBool() ) {
  41. return;
  42. }
  43. if ( !idStr::Icmp( cvarSystem->GetCVarString( "sys_arch" ), "winnt" ) ) {
  44. UnregisterHotKey( 0, 0 );
  45. } else {
  46. BOOL old;
  47. SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
  48. }
  49. s_alttab_disabled = false;
  50. }
  51. void WIN_Sizing(WORD side, RECT *rect)
  52. {
  53. if ( !glConfig.isInitialized || glConfig.vidHeight <= 0 || glConfig.vidWidth <= 0 ) {
  54. return;
  55. }
  56. if ( idKeyInput::IsDown( K_CTRL ) ) {
  57. return;
  58. }
  59. int width = rect->right - rect->left;
  60. int height = rect->bottom - rect->top;
  61. // Adjust width/height for window decoration
  62. RECT decoRect = { 0, 0, 0, 0 };
  63. AdjustWindowRect( &decoRect, WINDOW_STYLE|WS_SYSMENU, FALSE );
  64. int decoWidth = decoRect.right - decoRect.left;
  65. int decoHeight = decoRect.bottom - decoRect.top;
  66. width -= decoWidth;
  67. height -= decoHeight;
  68. // Clamp to a minimum size
  69. int minWidth = 160;
  70. int minHeight = minWidth * SCREEN_HEIGHT / SCREEN_WIDTH;
  71. if ( width < minWidth ) {
  72. width = minWidth;
  73. }
  74. if ( height < minHeight ) {
  75. height = minHeight;
  76. }
  77. // Set the new size
  78. switch ( side ) {
  79. case WMSZ_LEFT:
  80. rect->left = rect->right - width - decoWidth;
  81. rect->bottom = rect->top + ( width * SCREEN_HEIGHT / SCREEN_WIDTH ) + decoHeight;
  82. break;
  83. case WMSZ_RIGHT:
  84. rect->right = rect->left + width + decoWidth;
  85. rect->bottom = rect->top + ( width * SCREEN_HEIGHT / SCREEN_WIDTH ) + decoHeight;
  86. break;
  87. case WMSZ_BOTTOM:
  88. case WMSZ_BOTTOMRIGHT:
  89. rect->bottom = rect->top + height + decoHeight;
  90. rect->right = rect->left + ( height * SCREEN_WIDTH / SCREEN_HEIGHT ) + decoWidth;
  91. break;
  92. case WMSZ_TOP:
  93. case WMSZ_TOPRIGHT:
  94. rect->top = rect->bottom - height - decoHeight;
  95. rect->right = rect->left + ( height * SCREEN_WIDTH / SCREEN_HEIGHT ) + decoWidth;
  96. break;
  97. case WMSZ_BOTTOMLEFT:
  98. rect->bottom = rect->top + height + decoHeight;
  99. rect->left = rect->right - ( height * SCREEN_WIDTH / SCREEN_HEIGHT ) - decoWidth;
  100. break;
  101. case WMSZ_TOPLEFT:
  102. rect->top = rect->bottom - height - decoHeight;
  103. rect->left = rect->right - ( height * SCREEN_WIDTH / SCREEN_HEIGHT ) - decoWidth;
  104. break;
  105. }
  106. }
  107. #endif
  108. //==========================================================================
  109. // Keep this in sync with the one in win_input.cpp
  110. // This one is used in the menu, the other one is used in game
  111. static byte s_scantokey[128] =
  112. {
  113. // 0 1 2 3 4 5 6 7
  114. // 8 9 A B C D E F
  115. 0, 27, '1', '2', '3', '4', '5', '6',
  116. '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
  117. 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  118. 'o', 'p', '[', ']', K_ENTER,K_CTRL, 'a', 's', // 1
  119. 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
  120. '\'', '`', K_SHIFT, '\\', 'z', 'x', 'c', 'v', // 2
  121. 'b', 'n', 'm', ',', '.', '/', K_SHIFT, K_KP_STAR,
  122. K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
  123. K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
  124. K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
  125. K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, 0, K_F11,
  126. K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
  127. 0, 0, 0, 0, 0, 0, 0, 0,
  128. 0, 0, 0, 0, 0, 0, 0, 0, // 6
  129. 0, 0, 0, 0, 0, 0, 0, 0,
  130. 0, 0, 0, 0, 0, 0, 0, 0 // 7
  131. };
  132. static byte s_scantoshift[128] =
  133. {
  134. // 0 1 2 3 4 5 6 7
  135. // 8 9 A B C D E F
  136. 0, 27, '!', '@', '#', '$', '%', '^',
  137. '&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0
  138. 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
  139. 'O', 'P', '{', '}', K_ENTER,K_CTRL, 'A', 'S', // 1
  140. 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
  141. '|' , '~', K_SHIFT, '\\', 'Z', 'X', 'C', 'V', // 2
  142. 'B', 'N', 'M', '<', '>', '?', K_SHIFT, K_KP_STAR,
  143. K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3
  144. K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLL, K_HOME,
  145. K_UPARROW, K_PGUP, K_KP_MINUS,K_LEFTARROW,K_KP_5, K_RIGHTARROW,K_KP_PLUS,K_END, // 4
  146. K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, 0, K_F11,
  147. K_F12, 0, 0, K_LWIN, K_RWIN, K_MENU, 0, 0, // 5
  148. 0, 0, 0, 0, 0, 0, 0, 0,
  149. 0, 0, 0, 0, 0, 0, 0, 0, // 6
  150. 0, 0, 0, 0, 0, 0, 0, 0,
  151. 0, 0, 0, 0, 0, 0, 0, 0 // 7
  152. };
  153. /*
  154. =======
  155. MapKey
  156. Map from windows to Doom keynums
  157. =======
  158. */
  159. int MapKey (int key)
  160. {
  161. int result;
  162. int modified;
  163. bool is_extended;
  164. modified = ( key >> 16 ) & 255;
  165. if ( modified > 127 )
  166. return 0;
  167. if ( key & ( 1 << 24 ) ) {
  168. is_extended = true;
  169. }
  170. else {
  171. is_extended = false;
  172. }
  173. //Check for certain extended character codes.
  174. //The specific case we are testing is the numpad / is not being translated
  175. //properly for localized builds.
  176. if(is_extended) {
  177. switch(modified) {
  178. case 0x35: //Numpad /
  179. return K_KP_SLASH;
  180. }
  181. }
  182. const unsigned char *scanToKey = Sys_GetScanTable();
  183. result = scanToKey[modified];
  184. // common->Printf( "Key: 0x%08x Modified: 0x%02x Extended: %s Result: 0x%02x\n", key, modified, (is_extended?"Y":"N"), result);
  185. if ( is_extended ) {
  186. switch ( result )
  187. {
  188. case K_PAUSE:
  189. return K_KP_NUMLOCK;
  190. case 0x0D:
  191. return K_KP_ENTER;
  192. case 0x2F:
  193. return K_KP_SLASH;
  194. case 0xAF:
  195. return K_KP_PLUS;
  196. case K_KP_STAR:
  197. return K_PRINT_SCR;
  198. case K_ALT:
  199. return K_RIGHT_ALT;
  200. }
  201. }
  202. else {
  203. switch ( result )
  204. {
  205. case K_HOME:
  206. return K_KP_HOME;
  207. case K_UPARROW:
  208. return K_KP_UPARROW;
  209. case K_PGUP:
  210. return K_KP_PGUP;
  211. case K_LEFTARROW:
  212. return K_KP_LEFTARROW;
  213. case K_RIGHTARROW:
  214. return K_KP_RIGHTARROW;
  215. case K_END:
  216. return K_KP_END;
  217. case K_DOWNARROW:
  218. return K_KP_DOWNARROW;
  219. case K_PGDN:
  220. return K_KP_PGDN;
  221. case K_INS:
  222. return K_KP_INS;
  223. case K_DEL:
  224. return K_KP_DEL;
  225. }
  226. }
  227. return result;
  228. }
  229. #ifndef USE_SDL
  230. /*
  231. ====================
  232. MainWndProc
  233. main window procedure
  234. ====================
  235. */
  236. LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
  237. int key;
  238. switch( uMsg ) {
  239. case WM_WINDOWPOSCHANGED:
  240. if (glConfig.isInitialized) {
  241. RECT rect;
  242. if (::GetClientRect(win32.hWnd, &rect)) {
  243. glConfig.vidWidth = rect.right - rect.left;
  244. glConfig.vidHeight = rect.bottom - rect.top;
  245. }
  246. }
  247. break;
  248. case WM_CREATE:
  249. win32.hWnd = hWnd;
  250. if ( win32.cdsFullscreen ) {
  251. WIN_DisableAltTab();
  252. } else {
  253. WIN_EnableAltTab();
  254. }
  255. // do the OpenGL setup
  256. void GLW_WM_CREATE( HWND hWnd );
  257. GLW_WM_CREATE( hWnd );
  258. break;
  259. case WM_DESTROY:
  260. // let sound and input know about this?
  261. win32.hWnd = NULL;
  262. if ( win32.cdsFullscreen ) {
  263. WIN_EnableAltTab();
  264. }
  265. break;
  266. case WM_CLOSE:
  267. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit" );
  268. break;
  269. case WM_ACTIVATE:
  270. // if we got here because of an alt-tab or maximize,
  271. // we should activate immediately. If we are here because
  272. // the mouse was clicked on a title bar or drag control,
  273. // don't activate until the mouse button is released
  274. {
  275. int fActive, fMinimized;
  276. fActive = LOWORD(wParam);
  277. fMinimized = (BOOL) HIWORD(wParam);
  278. win32.activeApp = (fActive != WA_INACTIVE);
  279. if ( win32.activeApp ) {
  280. idKeyInput::ClearStates();
  281. com_editorActive = false;
  282. Sys_GrabMouseCursor( true );
  283. }
  284. if ( fActive == WA_INACTIVE ) {
  285. win32.movingWindow = false;
  286. }
  287. // start playing the game sound world
  288. session->SetPlayingSoundWorld();
  289. // we do not actually grab or release the mouse here,
  290. // that will be done next time through the main loop
  291. }
  292. break;
  293. case WM_MOVE: {
  294. int xPos, yPos;
  295. RECT r;
  296. int style;
  297. if (!win32.cdsFullscreen )
  298. {
  299. xPos = (short) LOWORD(lParam); // horizontal position
  300. yPos = (short) HIWORD(lParam); // vertical position
  301. r.left = 0;
  302. r.top = 0;
  303. r.right = 1;
  304. r.bottom = 1;
  305. style = GetWindowLong( hWnd, GWL_STYLE );
  306. AdjustWindowRect( &r, style, FALSE );
  307. win32.win_xpos.SetInteger( xPos + r.left );
  308. win32.win_ypos.SetInteger( yPos + r.top );
  309. win32.win_xpos.ClearModified();
  310. win32.win_ypos.ClearModified();
  311. }
  312. break;
  313. }
  314. case WM_TIMER: {
  315. if ( win32.win_timerUpdate.GetBool() ) {
  316. common->Frame();
  317. }
  318. break;
  319. }
  320. case WM_SYSCOMMAND:
  321. if ( wParam == SC_SCREENSAVE || wParam == SC_KEYMENU ) {
  322. return 0;
  323. }
  324. break;
  325. case WM_SYSKEYDOWN:
  326. if ( wParam == 13 ) { // alt-enter toggles full-screen
  327. cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() );
  328. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
  329. return 0;
  330. }
  331. // fall through for other keys
  332. case WM_KEYDOWN:
  333. key = MapKey( lParam );
  334. if ( key == K_CTRL || key == K_ALT || key == K_RIGHT_ALT ) {
  335. // let direct-input handle this because windows sends Alt-Gr
  336. // as two events (ctrl then alt)
  337. break;
  338. }
  339. Sys_QueEvent( win32.sysMsgTime, SE_KEY, key, true, 0, NULL );
  340. break;
  341. case WM_SYSKEYUP:
  342. case WM_KEYUP:
  343. key = MapKey( lParam );
  344. if ( key == K_PRINT_SCR ) {
  345. // don't queue printscreen keys. Since windows doesn't send us key
  346. // down events for this, we handle queueing them with DirectInput
  347. break;
  348. } else if ( key == K_CTRL || key == K_ALT || key == K_RIGHT_ALT ) {
  349. // let direct-input handle this because windows sends Alt-Gr
  350. // as two events (ctrl then alt)
  351. break;
  352. }
  353. Sys_QueEvent( win32.sysMsgTime, SE_KEY, key, false, 0, NULL );
  354. break;
  355. case WM_CHAR:
  356. Sys_QueEvent( win32.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL );
  357. break;
  358. case WM_NCLBUTTONDOWN:
  359. // win32.movingWindow = true;
  360. break;
  361. case WM_ENTERSIZEMOVE:
  362. win32.movingWindow = true;
  363. break;
  364. case WM_EXITSIZEMOVE:
  365. win32.movingWindow = false;
  366. break;
  367. case WM_SIZING:
  368. WIN_Sizing(wParam, (RECT *)lParam);
  369. break;
  370. case WM_RBUTTONDOWN:
  371. case WM_RBUTTONUP:
  372. case WM_MBUTTONDOWN:
  373. case WM_MBUTTONUP:
  374. case WM_MOUSEMOVE: {
  375. break;
  376. }
  377. case WM_MOUSEWHEEL: {
  378. int delta = GET_WHEEL_DELTA_WPARAM( wParam ) / WHEEL_DELTA;
  379. int key = delta < 0 ? K_MWHEELDOWN : K_MWHEELUP;
  380. delta = abs( delta );
  381. while( delta-- > 0 ) {
  382. Sys_QueEvent( win32.sysMsgTime, SE_KEY, key, true, 0, NULL );
  383. Sys_QueEvent( win32.sysMsgTime, SE_KEY, key, false, 0, NULL );
  384. }
  385. break;
  386. }
  387. }
  388. return DefWindowProc( hWnd, uMsg, wParam, lParam );
  389. }
  390. #endif