PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/CS/migrated/tags/R0_96_003/libs/cssys/win32/win32.cpp

#
C++ | 1111 lines | 957 code | 83 blank | 71 comment | 159 complexity | 673f8730542d87bcd1cbfb7b8794c899 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Copyright (C) 1998-2001 by Jorrit Tyberghein
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this library; if not, write to the Free
  13. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include <ctype.h>
  16. #include "cssysdef.h"
  17. #include "cssys/sysfunc.h"
  18. #include "cssys/win32/win32.h"
  19. #include "iutil/cfgmgr.h"
  20. #include "iutil/event.h"
  21. #include "iutil/eventq.h"
  22. #include "iutil/cmdline.h"
  23. #include "ivideo/graph2d.h"
  24. #include "ivideo/graph3d.h"
  25. #include "ivideo/natwin.h"
  26. #include <stdarg.h>
  27. #include <windows.h>
  28. #ifdef DO_DINPUT_KEYBOARD
  29. #include <dinput.h>
  30. #endif
  31. #include <stdio.h>
  32. #include <time.h>
  33. #if defined(COMP_VC)
  34. #include <sys/timeb.h>
  35. #endif
  36. #if defined(COMP_BC)
  37. #include <dos.h> // For _argc & _argv
  38. #endif
  39. #if defined(__CYGWIN__)
  40. // Cygwin doesn't understand _argc or _argv, so we define them here.
  41. // These are borrowed from Mingw32 includes (see stdlib.h)
  42. // Cygwin Purists, forgive the corruption, Cygwin means Cygnus for Win32.
  43. extern int _argc;
  44. extern char** _argv;
  45. #endif
  46. bool ApplicationActive = true;
  47. extern HINSTANCE ModuleHandle;
  48. extern int ApplicationShow;
  49. void SystemFatalError (char *s)
  50. {
  51. ChangeDisplaySettings (NULL, 0); // doesn't hurt
  52. fprintf(stderr, "FATAL: %s\n", s);
  53. MessageBox(NULL, s, "Fatal Error", MB_OK | MB_ICONSTOP);
  54. }
  55. #define MAX_SCANCODE 0x100
  56. #ifdef DO_DINPUT_KEYBOARD
  57. /*
  58. * This table performs the translation from keycode to Crystal Space key code.
  59. */
  60. static unsigned short ScanCodeToChar [MAX_SCANCODE] =
  61. {
  62. 0, CSKEY_ESC, '1', '2',
  63. '3', '4', '5', '6', // 00..07
  64. '7', '8', '9', '0',
  65. '-', '=', CSKEY_BACKSPACE,CSKEY_TAB, // 08..0F
  66. 'q', 'w', 'e', 'r',
  67. 't', 'y', 'u', 'i', // 10..17
  68. 'o', 'p', '[', ']',
  69. CSKEY_ENTER, CSKEY_CTRL, 'a', 's', // 18..1F
  70. 'd', 'f', 'g', 'h',
  71. 'j', 'k', 'l', ';', // 20..27
  72. 39, '`', CSKEY_SHIFT, '\\',
  73. 'z', 'x', 'c', 'v', // 28..2F
  74. 'b', 'n', 'm', ',',
  75. '.', '/', CSKEY_SHIFT, CSKEY_PADMULT,// 30..37
  76. CSKEY_ALT, ' ', 0, CSKEY_F1,
  77. CSKEY_F2, CSKEY_F3, CSKEY_F4, CSKEY_F5, // 38..3F
  78. CSKEY_F6, CSKEY_F7, CSKEY_F8, CSKEY_F9,
  79. CSKEY_F10, 0, 0, CSKEY_HOME, // 40..47
  80. CSKEY_UP, CSKEY_PGUP, CSKEY_PADMINUS, CSKEY_LEFT,
  81. CSKEY_CENTER, CSKEY_RIGHT, CSKEY_PADPLUS, CSKEY_END, // 48..4F
  82. CSKEY_DOWN, CSKEY_PGDN, CSKEY_INS, CSKEY_DEL,
  83. 0, 0, 0, CSKEY_F11, // 50..57
  84. CSKEY_F12, 0, 0, 0,
  85. 0, 0, 0, 0, // 58..5F
  86. 0, 0, 0, 0,
  87. 0, 0, 0, 0, // 60..67
  88. 0, 0, 0, 0,
  89. 0, 0, 0, 0, // 68..6F
  90. 0, 0, 0, 0,
  91. 0, 0, 0, 0, // 70..77
  92. 0, 0, 0, 0,
  93. 0, 0, 0, 0, // 78..7F
  94. 0, 0, 0, 0,
  95. 0, 0, 0, 0, // 80..87
  96. 0, 0, 0, 0,
  97. 0, 0, 0, 0, // 88..8F
  98. 0, 0, 0, 0,
  99. 0, 0, 0, 0, // 90..97
  100. 0, 0, 0, 0,
  101. CSKEY_ENTER, CSKEY_CTRL, 0, 0, // 98..9F
  102. 0, 0, 0, 0,
  103. 0, 0, 0, 0, // A0..A7
  104. 0, 0, 0, 0,
  105. 0, 0, 0, 0, // A8..AF
  106. 0, 0, 0, ',',
  107. 0, CSKEY_PADDIV, 0, 0, // B0..B7
  108. CSKEY_ALT, 0, 0, 0,
  109. 0, 0, 0, 0, // B8..BF
  110. 0, 0, 0, 0,
  111. 0, 0, 0, CSKEY_HOME, // C0..C7
  112. CSKEY_UP, CSKEY_PGUP, 0, CSKEY_LEFT,
  113. 0, CSKEY_RIGHT, 0, CSKEY_END, // C8..CF
  114. CSKEY_DOWN, CSKEY_PGDN, CSKEY_INS, CSKEY_DEL,
  115. 0, 0, 0, 0, // D0..D7
  116. 0, 0, 0, 0,
  117. 0, 0, 0, 0, // D8..DF
  118. 0, 0, 0, 0,
  119. 0, 0, 0, 0, // E0..E7
  120. 0, 0, 0, 0,
  121. 0, 0, 0, 0, // E8..EF
  122. 0, 0, 0, 0,
  123. 0, 0, 0, 0, // F0..F7
  124. 0, 0, 0, 0,
  125. 0, 0, 0, 0 // F8..FF
  126. };
  127. // This macro is for COM calls. If it fails, it shows a MessageBox then
  128. // kills the whole process. It's brutal, but as I use another thread,
  129. // it's safer this way
  130. #define CHK_FAILED(x) \
  131. { if(FAILED(x)) { MessageBox(NULL, #x " Failed!", NULL,MB_OK|MB_ICONERROR); ::ExitProcess(1); } }
  132. // This macro is for COM Release calls
  133. #define CHK_RELEASE(x) \
  134. { if((x) != NULL) { (x)->Release(); (x)=NULL; } }
  135. /*
  136. * The thread entry point. Called by ::Open()
  137. */
  138. #define AUTOREPEAT_WAITTIME 1000 // 1 seconde
  139. #define AUTOREPEAT_TIME 100 // 10 keystroke/seconds
  140. DWORD WINAPI s_threadroutine (LPVOID param)
  141. {
  142. iEventOutlet *EventOutlet = (iEventOutlet *)param;
  143. HRESULT hr;
  144. DWORD dwWait = INFINITE;
  145. char *buffer;
  146. int i,lastkey = -1;
  147. #ifndef DI_USEGETDEVICEDATA
  148. char *oldbuffer = NULL;
  149. #endif
  150. LPDIRECTINPUT lpdi = NULL;
  151. LPDIRECTINPUTDEVICE lpKbd = NULL;
  152. //Setup for directinput mouse code
  153. LPDIRECTINPUTDEVICE lpMouse = NULL;
  154. HANDLE hEvent [2];
  155. CHK_FAILED (DirectInputCreate (ModuleHandle, DIRECTINPUT_VERSION, &lpdi, NULL));
  156. CHK_FAILED (lpdi->CreateDevice (GUID_SysKeyboard, &lpKbd, NULL));
  157. CHK_FAILED (lpKbd->SetDataFormat (&c_dfDIKeyboard));
  158. CHK_FAILED (lpKbd->SetCooperativeLevel (FindWindow (WINDOWCLASSNAME, NULL),
  159. DISCL_FOREGROUND | DISCL_NONEXCLUSIVE));
  160. //Setup for directinput mouse code
  161. #if 0
  162. CHK_FAILED(lpdi->CreateDevice (GUID_SysMouse, &lpMouse, NULL));
  163. CHK_FAILED(lpMouse->SetDataFormat(&c_dfDIMouse));
  164. CHK_FAILED(lpMouse->SetCooperativeLevel(FindWindow (WINDOWCLASSNAME, NULL),
  165. DISCL_EXCLUSIVE | DISCL_FOREGROUND));
  166. hevtMouse = CreateEvent(0, 0, 0, 0);
  167. CHK_FAILED(lpMouse->SetEventNotification(g_hevtMouse));
  168. DIPROPDWORD dipdw =
  169. {
  170. {
  171. sizeof(DIPROPDWORD), // diph.dwSize
  172. sizeof(DIPROPHEADER), // diph.dwHeaderSize
  173. 0, // diph.dwObj
  174. DIPH_DEVICE, // diph.dwHow
  175. },
  176. DINPUT_BUFFERSIZE, // dwData
  177. };
  178. CHK_FAILED(lpMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph));
  179. #endif
  180. #ifdef DI_USEGETDEVICEDATA
  181. {
  182. DIPROPDWORD dpd;
  183. dpd.diph.dwSize=sizeof(DIPROPDWORD);
  184. dpd.diph.dwHeaderSize=sizeof(DIPROPHEADER);
  185. dpd.diph.dwObj=0;
  186. dpd.diph.dwHow=DIPH_DEVICE;
  187. dpd.dwData=10; // The size of the buffer (should be more than sufficient)
  188. #if DIRECTINPUT_VERSION < 0x0700
  189. CHK_FAILED (lpKbd->SetProperty (DIPROP_BUFFERSIZE, &dpd));
  190. #else
  191. //For incomprehensible reason, SetProperty() parameters type has
  192. //changed between DX6.1 and DX7 SDK
  193. CHK_FAILED (lpKbd->SetProperty (DIPROP_BUFFERSIZE, &dpd.diph));
  194. #endif
  195. }
  196. #endif
  197. hEvent [0] = CreateEvent (NULL, FALSE, FALSE, NULL);
  198. if (hEvent [0] == NULL)
  199. {
  200. MessageBox (NULL, "CreateEvent() Failed!", NULL, MB_OK|MB_ICONERROR);
  201. ExitProcess (1);
  202. }
  203. if (!DuplicateHandle (GetCurrentProcess(), ((SysSystemDriver*)System)->m_hEvent,
  204. GetCurrentProcess (), &hEvent [1], 0, FALSE, DUPLICATE_SAME_ACCESS))
  205. {
  206. MessageBox (NULL, "DuplicateEvent() Failed!", NULL, MB_OK|MB_ICONERROR);
  207. ExitProcess (1);
  208. }
  209. hr = lpKbd->SetEventNotification (hEvent [0]);
  210. switch (hr)
  211. {
  212. case DI_OK:
  213. break;
  214. default:
  215. MessageBox (NULL, "lpKbd->SetEventNotification(hEvent) Failed!", NULL,
  216. MB_OK|MB_ICONERROR);
  217. ExitProcess (1);
  218. break;
  219. }
  220. while (1)
  221. {
  222. hr = lpKbd->Acquire ();
  223. if (SUCCEEDED (hr))
  224. break;
  225. if (WaitForSingleObject (hEvent [1], 0) == WAIT_OBJECT_0 + 1)
  226. {
  227. CloseHandle (hEvent [0]);
  228. CloseHandle (hEvent [1]);
  229. CHK_RELEASE (lpKbd);
  230. CHK_RELEASE (lpdi);
  231. #ifndef DI_USEGETDEVICEDATA
  232. if (oldbuffer) delete[] oldbuffer;
  233. #endif
  234. return 0;
  235. }
  236. }
  237. #ifndef DI_USEGETDEVICEDATA
  238. oldbuffer = new char [256];
  239. hr = lpKbd->GetDeviceState (256, oldbuffer);
  240. #endif
  241. while (1)
  242. {
  243. switch (WaitForMultipleObjects (2, hEvent, FALSE, dwWait))
  244. {
  245. case WAIT_OBJECT_0:
  246. #ifndef DI_USEGETDEVICEDATA
  247. buffer = new char [256];
  248. do
  249. {
  250. hr = lpKbd->GetDeviceState (256, buffer);
  251. switch (hr)
  252. {
  253. case DIERR_NOTACQUIRED:
  254. case DIERR_INPUTLOST:
  255. lpKbd->Acquire ();
  256. break;
  257. case DI_OK:
  258. break;
  259. default:
  260. MessageBox (NULL, "lpKbd->GetDeviceState(hEvent) Failed!",
  261. NULL, MB_OK|MB_ICONERROR);
  262. ExitProcess (1);
  263. break;
  264. }
  265. } while (hr != DI_OK);
  266. for (i = 0; i < 256; i++)
  267. if (oldbuffer [i] != buffer [i])
  268. {
  269. if (buffer [i] & 0X80)
  270. {
  271. lastkey = i;
  272. dwWait = AUTOREPEAT_WAITTIME;
  273. EventOutlet->Key (ScanCodeToChar [i], -1, true);
  274. }
  275. else
  276. {
  277. lastkey = -1;
  278. dwWait = INFINITE;
  279. EventOutlet->Key (ScanCodeToChar[i], -1, false);
  280. }
  281. break;
  282. }
  283. delete [] oldbuffer;
  284. oldbuffer = buffer;
  285. #else
  286. DIDEVICEOBJECTDATA *lpdidod;
  287. DWORD dwNb;
  288. do
  289. {
  290. dwNb = INFINITE;
  291. hr = lpKbd->GetDeviceData (sizeof (DIDEVICEOBJECTDATA), NULL, &dwNb,DIGDD_PEEK);
  292. switch(hr)
  293. {
  294. case DIERR_NOTACQUIRED:
  295. case DIERR_INPUTLOST:
  296. lpKbd->Acquire ();
  297. break;
  298. case DI_OK:
  299. break;
  300. case DI_BUFFEROVERFLOW:
  301. hr = DI_OK;
  302. break;
  303. default:
  304. MessageBox(NULL, "lpKbd->GetDeviceState(hEvent) Failed!",
  305. NULL, MB_OK|MB_ICONERROR);
  306. ExitProcess (1);
  307. break;
  308. }
  309. } while (hr != DI_OK);
  310. if (!dwNb)
  311. continue;
  312. lpdidod = new DIDEVICEOBJECTDATA [dwNb];
  313. CHK_FAILED (lpKbd->GetDeviceData (sizeof (DIDEVICEOBJECTDATA),
  314. lpdidod, &dwNb, 0));
  315. for (i = 0; i < dwNb; i++)
  316. {
  317. if (lpdidod [i].dwData & 0X80)
  318. {
  319. lastkey = lpdidod [i].dwOfs;
  320. dwWait = AUTOREPEAT_WAITTIME:
  321. EventOutlet->Key (ScanCodeToChar [lpdidod [i].dwOfs], -1, true);
  322. }
  323. else
  324. {
  325. lastkey = -1;
  326. dwWait = INFINITE;
  327. EventOutlet->Key (ScanCodeToChar [lpdidod [i].dwOfs], -1, false);
  328. }
  329. }
  330. delete[] lpdidod;
  331. #endif
  332. break;
  333. case WAIT_TIMEOUT: // HANDLE key autorepeat
  334. buffer = new char [256];
  335. do
  336. {
  337. hr = lpKbd->GetDeviceState (256, buffer);
  338. switch (hr)
  339. {
  340. case DIERR_NOTACQUIRED:
  341. case DIERR_INPUTLOST:
  342. lpKbd->Acquire ();
  343. break;
  344. case DI_OK:
  345. break;
  346. default:
  347. MessageBox (NULL, "lpKbd->GetDeviceState(hEvent) Failed!",
  348. NULL, MB_OK|MB_ICONERROR);
  349. ExitProcess (1);
  350. break;
  351. }
  352. } while (hr != DI_OK);
  353. // The lastkey is still pressed
  354. if ((lastkey >= 0) && (buffer [lastkey] & 0X80))
  355. {
  356. dwWait = AUTOREPEAT_TIME;
  357. EventOutlet->Key (ScanCodeToChar [lastkey], -1, true);
  358. }
  359. else
  360. { // Strange.. we didn't get the message that the key was released !
  361. lastkey = -1;
  362. dwWait = INFINITE;
  363. }
  364. delete [] buffer;
  365. break;
  366. case WAIT_OBJECT_0 + 1:
  367. lpKbd->Unacquire ();
  368. CloseHandle (hEvent [0]);
  369. CloseHandle (hEvent [1]);
  370. CHK_RELEASE (lpKbd);
  371. CHK_RELEASE (lpdi);
  372. #ifndef DI_USEGETDEVICEDATA
  373. if (oldbuffer)
  374. delete [] oldbuffer;
  375. #endif
  376. return 0;
  377. }
  378. }
  379. }
  380. #undef CHK_RELEASE
  381. #undef CHK_FAILED
  382. #endif // DO_DINPUT_KEYBOARD
  383. class Win32Assistant :
  384. public iWin32Assistant,
  385. public iEventPlug,
  386. public iEventHandler
  387. {
  388. private:
  389. iObjectRegistry* registry;
  390. /// is a console window to be displayed?
  391. bool console_window;
  392. /// is the binary linked as GUI or console app?
  393. bool is_console_app;
  394. /// is command line help requested?
  395. bool cmdline_help_wanted;
  396. HCURSOR m_hCursor;
  397. csRef<iEventOutlet> EventOutlet;
  398. void SetWinCursor (HCURSOR);
  399. iEventOutlet* GetEventOutlet();
  400. static LRESULT CALLBACK WindowProc (HWND hWnd, UINT message,
  401. WPARAM wParam, LPARAM lParam);
  402. #ifdef DO_DINPUT_KEYBOARD
  403. HANDLE m_hEvent;
  404. HANDLE m_hThread;
  405. friend DWORD WINAPI s_threadroutine(LPVOID param);
  406. #endif
  407. public:
  408. SCF_DECLARE_IBASE;
  409. Win32Assistant (iObjectRegistry*);
  410. virtual ~Win32Assistant ();
  411. virtual void Shutdown();
  412. virtual HINSTANCE GetInstance () const;
  413. virtual bool GetIsActive () const;
  414. virtual int GetCmdShow () const;
  415. virtual bool SetCursor (int cursor);
  416. virtual bool HandleEvent (iEvent&);
  417. virtual unsigned GetPotentiallyConflictingEvents ();
  418. virtual unsigned QueryEventPriority (unsigned);
  419. virtual void DisableConsole ();
  420. void AlertV (HWND window, int type, const char* title,
  421. const char* okMsg, const char* msg, va_list args);
  422. };
  423. static Win32Assistant* GLOBAL_ASSISTANT = 0;
  424. SCF_IMPLEMENT_IBASE (Win32Assistant)
  425. SCF_IMPLEMENTS_INTERFACE (iWin32Assistant)
  426. SCF_IMPLEMENTS_INTERFACE (iEventPlug)
  427. SCF_IMPLEMENTS_INTERFACE (iEventHandler)
  428. SCF_IMPLEMENT_IBASE_END
  429. static void ToLower (char *dst, const char *src)
  430. {
  431. char *d=dst;
  432. const char *s=src;
  433. for(; *s; s++, d++) {
  434. *d = (char)tolower(*s);
  435. }
  436. *d=0;
  437. }
  438. bool csPlatformStartup(iObjectRegistry* r)
  439. {
  440. /*
  441. When it isn't already in the PATH environment,
  442. the CS directory will be put there in fornt of all
  443. other paths.
  444. The idea is that DLLs required by plugins (e.g. zlib)
  445. which reside in the CS directory can be found by the
  446. OS even if the application is somewhere else.
  447. */
  448. // check if installdir is in the path.
  449. bool gotpath = false;
  450. char installDir[MAX_PATH];
  451. csGetInstallPath(installDir, sizeof(installDir));
  452. size_t idlen = strlen(installDir);
  453. // csGetInstallDir() might return "" (current dir)
  454. if (idlen != 0)
  455. {
  456. ToLower (installDir, installDir);
  457. idlen--;
  458. installDir[idlen] = 0;
  459. const char* path = getenv("PATH");
  460. if (path)
  461. {
  462. char *mypath = new char[strlen(path) + 1];
  463. ToLower (mypath, path);
  464. char* ppos = strstr (mypath, installDir);
  465. while (!gotpath && ppos)
  466. {
  467. char* npos = strchr (ppos, ';');
  468. if (npos) *npos = 0;
  469. if ((strlen (ppos) == idlen) || (strlen (ppos) == idlen+1))
  470. {
  471. if (ppos[idlen] == '\\') ppos[idlen] = 0;
  472. if (!strcmp (ppos, installDir))
  473. {
  474. // found it
  475. gotpath = true;
  476. }
  477. }
  478. ppos = npos ? strstr (npos+1, installDir) : NULL;
  479. }
  480. delete[] mypath;
  481. }
  482. if (!gotpath)
  483. {
  484. // put CRYSTAL path into PATH environment.
  485. char *newpath = new char[(path?strlen(path):0) + strlen(installDir) + 2];
  486. strcpy (newpath, installDir);
  487. strcat (newpath, ";");
  488. if (path) strcat (newpath, path);
  489. SetEnvironmentVariable ("PATH", newpath);
  490. delete[] newpath;
  491. }
  492. }
  493. Win32Assistant* a = new Win32Assistant(r);
  494. bool ok = r->Register (static_cast<iWin32Assistant*>(a), "iWin32Assistant");
  495. if (ok)
  496. GLOBAL_ASSISTANT = a;
  497. else
  498. {
  499. a->DecRef();
  500. SystemFatalError ("Failed to register iWin32Assistant!");
  501. }
  502. return ok;
  503. }
  504. bool csPlatformShutdown(iObjectRegistry* r)
  505. {
  506. if (GLOBAL_ASSISTANT != 0)
  507. {
  508. r->Unregister(
  509. static_cast<iWin32Assistant*>(GLOBAL_ASSISTANT), "iWin32Assistant");
  510. GLOBAL_ASSISTANT->Shutdown();
  511. GLOBAL_ASSISTANT->DecRef();
  512. GLOBAL_ASSISTANT = 0;
  513. }
  514. return true;
  515. }
  516. Win32Assistant::Win32Assistant (iObjectRegistry* r) :
  517. console_window (false),
  518. is_console_app(false),
  519. cmdline_help_wanted(false),
  520. EventOutlet (0)
  521. {
  522. SCF_CONSTRUCT_IBASE(0);
  523. if (ModuleHandle == NULL)
  524. ModuleHandle = GetModuleHandle(NULL);
  525. // Cygwin has problems with freopen()
  526. #if defined(CS_DEBUG) || defined(__CYGWIN__)
  527. console_window = true;
  528. #else
  529. console_window = false;
  530. #endif
  531. csRef<iCommandLineParser> cmdline (CS_QUERY_REGISTRY (r, iCommandLineParser));
  532. console_window = cmdline->GetBoolOption ("console", console_window);
  533. cmdline_help_wanted = cmdline->GetOption ("help");
  534. /*
  535. to determine if we are actually a console we app we look up
  536. the subsystem field in the PE header.
  537. */
  538. PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)ModuleHandle;
  539. PIMAGE_NT_HEADERS NTheader = (PIMAGE_NT_HEADERS)((int)dosHeader + dosHeader->e_lfanew);
  540. if (NTheader->Signature == 0x00004550) // check for PE sig
  541. {
  542. is_console_app =
  543. (NTheader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
  544. }
  545. /*
  546. - console apps won't do anything about their console... yet.
  547. - GUI apps will open a console window if desired.
  548. */
  549. if (!is_console_app)
  550. {
  551. if (console_window || cmdline_help_wanted)
  552. {
  553. AllocConsole ();
  554. freopen("CONOUT$", "a", stderr);
  555. freopen("CONOUT$", "a", stdout);
  556. freopen("CONIN$", "a", stdin);
  557. }
  558. }
  559. registry = r;
  560. registry->IncRef();
  561. WNDCLASS wc;
  562. wc.hCursor = NULL;
  563. // try the app icon...
  564. wc.hIcon = LoadIcon (ModuleHandle, MAKEINTRESOURCE(1));
  565. // not? maybe executable.ico?
  566. if (!wc.hIcon)
  567. {
  568. char apppath[MAX_PATH];
  569. GetModuleFileName (0, apppath, sizeof(apppath));
  570. char *dot = strrchr (apppath, '.');
  571. if (dot)
  572. {
  573. strcpy (dot, ".ico");
  574. }
  575. else
  576. {
  577. strcat (apppath, ".ico");
  578. }
  579. wc.hIcon = (HICON)LoadImage (ModuleHandle, apppath, IMAGE_ICON,
  580. 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
  581. }
  582. // finally the default one
  583. if (!wc.hIcon) wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  584. wc.lpszMenuName = NULL;
  585. wc.lpszClassName = CS_WIN32_WINDOW_CLASS_NAME;
  586. wc.hbrBackground = ::CreateSolidBrush(RGB(0, 0, 0));
  587. wc.hInstance = ModuleHandle;
  588. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  589. wc.lpfnWndProc = WindowProc;
  590. wc.cbClsExtra = 0;
  591. wc.cbWndExtra = 0;
  592. bool bResult = false;
  593. if (RegisterClass (&wc))
  594. bResult = true;
  595. m_hCursor = LoadCursor (0, IDC_ARROW);
  596. csRef<iEventQueue> q (CS_QUERY_REGISTRY (registry, iEventQueue));
  597. CS_ASSERT (q != NULL);
  598. q->RegisterListener (this, CSMASK_Nothing | CSMASK_Broadcast);
  599. }
  600. Win32Assistant::~Win32Assistant ()
  601. {
  602. registry->DecRef();
  603. if (!is_console_app && (console_window || cmdline_help_wanted))
  604. FreeConsole();
  605. }
  606. void Win32Assistant::Shutdown()
  607. {
  608. csRef<iEventQueue> q (CS_QUERY_REGISTRY (registry, iEventQueue));
  609. if (q != 0)
  610. q->RemoveListener(this);
  611. if (!is_console_app && (cmdline_help_wanted || console_window))
  612. {
  613. fprintf (stdout, "\nPress a key to close this window...");
  614. HANDLE hConsole = GetStdHandle (STD_INPUT_HANDLE);
  615. INPUT_RECORD ir;
  616. DWORD events_read;
  617. do
  618. {
  619. ReadConsoleInput (hConsole, &ir, 1, &events_read);
  620. } while ((events_read == 0) || (ir.EventType != KEY_EVENT));
  621. CloseHandle (hConsole);
  622. }
  623. }
  624. void Win32Assistant::SetWinCursor (HCURSOR cur)
  625. {
  626. m_hCursor = cur;
  627. ::SetCursor (cur);
  628. }
  629. unsigned Win32Assistant::GetPotentiallyConflictingEvents ()
  630. { return CSEVTYPE_Keyboard | CSEVTYPE_Mouse; }
  631. unsigned Win32Assistant::QueryEventPriority (unsigned /*iType*/)
  632. { return 100; }
  633. iEventOutlet* Win32Assistant::GetEventOutlet()
  634. {
  635. if (!EventOutlet.IsValid())
  636. {
  637. csRef<iEventQueue> q (CS_QUERY_REGISTRY(registry, iEventQueue));
  638. if (q != 0)
  639. EventOutlet = q->CreateEventOutlet(this);
  640. }
  641. return EventOutlet;
  642. }
  643. bool Win32Assistant::HandleEvent (iEvent& e)
  644. {
  645. if (e.Type != csevBroadcast)
  646. return false;
  647. if (e.Command.Code == cscmdPreProcess)
  648. {
  649. MSG msg;
  650. while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  651. {
  652. if (!GetMessage (&msg, NULL, 0, 0))
  653. {
  654. iEventOutlet* outlet = GetEventOutlet();
  655. outlet->Broadcast (cscmdQuit);
  656. return true;
  657. }
  658. TranslateMessage (&msg);
  659. DispatchMessage (&msg);
  660. }
  661. return true;
  662. }
  663. else if (e.Command.Code == cscmdSystemOpen)
  664. {
  665. # ifdef DO_DINPUT_KEYBOARD
  666. DWORD dwThreadId;
  667. m_hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  668. m_hThread =
  669. CreateThread (NULL, 0, s_threadroutine, EventOutlet, 0, &dwThreadId);
  670. if (!m_hEvent || !m_hThread)
  671. {
  672. MessageBox (NULL, "CreateEvent() Failed!", NULL, MB_OK|MB_ICONERROR);
  673. ExitProcess (1);
  674. }
  675. # endif
  676. return true;
  677. }
  678. else if (e.Command.Code == cscmdSystemClose)
  679. {
  680. # ifdef DO_DINPUT_KEYBOARD
  681. if (m_hEvent)
  682. {
  683. SetEvent (m_hEvent);
  684. CloseHandle (m_hEvent);
  685. m_hEvent = NULL;
  686. WaitForSingleObject (m_hThread, 1000);
  687. CloseHandle (m_hThread);
  688. m_hThread = NULL;
  689. }
  690. # endif
  691. }
  692. else if (e.Command.Code == cscmdCommandLineHelp)
  693. {
  694. #ifdef CS_DEBUG
  695. const char *defcon = "yes";
  696. #else
  697. const char *defcon = "no";
  698. #endif
  699. printf ("Win32-specific options:\n");
  700. printf (" -[no]console Create a debug console (default = %s)\n",
  701. defcon);
  702. }
  703. return false;
  704. }
  705. HINSTANCE Win32Assistant::GetInstance () const
  706. {
  707. return ModuleHandle;
  708. }
  709. bool Win32Assistant::GetIsActive () const
  710. {
  711. return ApplicationActive;
  712. }
  713. int Win32Assistant::GetCmdShow () const
  714. {
  715. return ApplicationShow;
  716. }
  717. #ifndef DO_DINPUT_KEYBOARD
  718. //----------------------------------------// Windows input translator //------//
  719. /*
  720. This table does not contain special key codes, since those are
  721. handled by the switch() in WinKeyTrans().
  722. */
  723. static unsigned char ScanCodeToChar [MAX_SCANCODE] =
  724. {
  725. 0, 0, '1', '2',
  726. '3', '4', '5', '6', // 00..07
  727. '7', '8', '9', '0',
  728. '-', '=', 0, 0, // 08..0F
  729. 'q', 'w', 'e', 'r',
  730. 't', 'y', 'u', 'i', // 10..17
  731. 'o', 'p', '[', ']',
  732. 0, 0, 'a', 's', // 18..1F
  733. 'd', 'f', 'g', 'h',
  734. 'j', 'k', 'l', ';', // 20..27
  735. 39, '`', 0, '\\',
  736. 'z', 'x', 'c', 'v', // 28..2F
  737. 'b', 'n', 'm', ',',
  738. '.', '/', 0, 0, // 30..37
  739. 0, ' ', 0, 0
  740. };
  741. static unsigned char LastCharCode [MAX_SCANCODE];
  742. static void WinKeyTrans (WPARAM wParam, bool down, iEventOutlet* outlet)
  743. {
  744. int key = 0, chr = 0;
  745. switch (wParam)
  746. {
  747. case VK_MENU: key = CSKEY_ALT; break;
  748. case VK_CONTROL: key = CSKEY_CTRL; break;
  749. case VK_SHIFT: key = CSKEY_SHIFT; break;
  750. case VK_UP: key = CSKEY_UP; break;
  751. case VK_DOWN: key = CSKEY_DOWN; break;
  752. case VK_LEFT: key = CSKEY_LEFT; break;
  753. case VK_RIGHT: key = CSKEY_RIGHT; break;
  754. case VK_CLEAR: key = CSKEY_CENTER; break;
  755. case VK_INSERT: key = CSKEY_INS; break;
  756. case VK_DELETE: key = CSKEY_DEL; break;
  757. case VK_PRIOR: key = CSKEY_PGUP; break;
  758. case VK_NEXT: key = CSKEY_PGDN; break;
  759. case VK_HOME: key = CSKEY_HOME; break;
  760. case VK_END: key = CSKEY_END; break;
  761. case VK_RETURN: key = CSKEY_ENTER; chr = '\n'; break;
  762. case VK_BACK: key = CSKEY_BACKSPACE; chr = '\b'; break;
  763. case VK_TAB: key = CSKEY_TAB; chr = '\t'; break;
  764. case VK_ESCAPE: key = CSKEY_ESC; chr = 27; break;
  765. case VK_F1: key = CSKEY_F1; break;
  766. case VK_F2: key = CSKEY_F2; break;
  767. case VK_F3: key = CSKEY_F3; break;
  768. case VK_F4: key = CSKEY_F4; break;
  769. case VK_F5: key = CSKEY_F5; break;
  770. case VK_F6: key = CSKEY_F6; break;
  771. case VK_F7: key = CSKEY_F7; break;
  772. case VK_F8: key = CSKEY_F8; break;
  773. case VK_F9: key = CSKEY_F9; break;
  774. case VK_F10: key = CSKEY_F10; break;
  775. case VK_F11: key = CSKEY_F11; break;
  776. case VK_F12: key = CSKEY_F12; break;
  777. case VK_ADD: key = CSKEY_PADPLUS; chr = '+'; break;
  778. case VK_SUBTRACT: key = CSKEY_PADMINUS; chr = '-'; break;
  779. case VK_MULTIPLY: key = CSKEY_PADMULT; chr = '*'; break;
  780. case VK_DIVIDE: key = CSKEY_PADDIV; chr = '/'; break;
  781. }
  782. if (key)
  783. outlet->Key (key, chr, down);
  784. }
  785. #endif
  786. LRESULT CALLBACK Win32Assistant::WindowProc (HWND hWnd, UINT message,
  787. WPARAM wParam, LPARAM lParam)
  788. {
  789. switch (message)
  790. {
  791. case WM_ACTIVATEAPP:
  792. if (wParam) { ApplicationActive = true; } else { ApplicationActive = false; }
  793. #ifndef DO_DINPUT_KEYBOARD
  794. memset (&LastCharCode, 0, sizeof (LastCharCode));
  795. #endif
  796. break;
  797. case WM_ACTIVATE:
  798. if (GLOBAL_ASSISTANT != 0)
  799. {
  800. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  801. outlet->Broadcast (cscmdFocusChanged,
  802. (void *)(LOWORD (wParam) != WA_INACTIVE));
  803. }
  804. break;
  805. case WM_CREATE:
  806. if (GLOBAL_ASSISTANT != 0)
  807. {
  808. // a window is created. Hide the console window, if requested.
  809. if (GLOBAL_ASSISTANT->is_console_app &&
  810. !GLOBAL_ASSISTANT->console_window)
  811. {
  812. GLOBAL_ASSISTANT->DisableConsole ();
  813. }
  814. }
  815. break;
  816. case WM_DESTROY:
  817. PostQuitMessage (0);
  818. return 0L;
  819. #ifndef DO_DINPUT_KEYBOARD
  820. case WM_SYSCHAR:
  821. case WM_CHAR:
  822. {
  823. if (GLOBAL_ASSISTANT != 0)
  824. {
  825. int scancode = (lParam >> 16) & 0xff;
  826. int key = (scancode < MAX_SCANCODE) ? ScanCodeToChar [scancode] : 0;
  827. if (key || (wParam >= ' '))
  828. {
  829. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  830. outlet->Key (key, wParam, true);
  831. LastCharCode [scancode] = (unsigned char) wParam;
  832. }
  833. }
  834. break;
  835. }
  836. case WM_KEYDOWN:
  837. case WM_SYSKEYDOWN:
  838. {
  839. if (GLOBAL_ASSISTANT != 0)
  840. {
  841. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  842. WinKeyTrans (wParam, true, outlet);
  843. if (wParam == VK_MENU) return 0;
  844. }
  845. break;
  846. }
  847. case WM_KEYUP:
  848. case WM_SYSKEYUP:
  849. {
  850. if (GLOBAL_ASSISTANT != 0)
  851. {
  852. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  853. WinKeyTrans (wParam, false, outlet);
  854. if (wParam == VK_MENU) return 0;
  855. // Check if this is the keyup event for a former WM_CHAR
  856. int scancode = (lParam >> 16) & 0xff;
  857. if ((scancode < MAX_SCANCODE) && LastCharCode [scancode])
  858. {
  859. int key = (scancode < MAX_SCANCODE) ? ScanCodeToChar [scancode] : 0;
  860. outlet->Key (key, LastCharCode [scancode], false);
  861. LastCharCode [scancode] = 0;
  862. }
  863. }
  864. break;
  865. }
  866. #endif
  867. case WM_LBUTTONDOWN:
  868. case WM_RBUTTONDOWN:
  869. case WM_MBUTTONDOWN:
  870. {
  871. if (GLOBAL_ASSISTANT != 0)
  872. {
  873. SetCapture (hWnd);
  874. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  875. outlet->Mouse ((message == WM_LBUTTONDOWN) ? 1 :
  876. (message == WM_RBUTTONDOWN) ? 2 : 3, true,
  877. short (LOWORD (lParam)), short (HIWORD (lParam)));
  878. }
  879. return TRUE;
  880. }
  881. case WM_LBUTTONUP:
  882. case WM_RBUTTONUP:
  883. case WM_MBUTTONUP:
  884. {
  885. if (GLOBAL_ASSISTANT != 0)
  886. {
  887. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  888. ReleaseCapture ();
  889. outlet->Mouse ((message == WM_LBUTTONUP) ? 1 :
  890. (message == WM_RBUTTONUP) ? 2 : 3, false,
  891. short (LOWORD (lParam)), short (HIWORD (lParam)));
  892. }
  893. return TRUE;
  894. }
  895. case WM_MOUSEMOVE:
  896. {
  897. if (GLOBAL_ASSISTANT != 0)
  898. {
  899. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  900. ::SetCursor (GLOBAL_ASSISTANT->m_hCursor);
  901. outlet->Mouse (0, false, short(LOWORD(lParam)), short(HIWORD(lParam)));
  902. }
  903. return TRUE;
  904. }
  905. case WM_SIZE:
  906. {
  907. if (GLOBAL_ASSISTANT != 0)
  908. {
  909. if ( (wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED) )
  910. {
  911. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  912. outlet->Broadcast (cscmdCanvasExposed, NULL);
  913. }
  914. else if (wParam == SIZE_MINIMIZED)
  915. {
  916. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  917. outlet->Broadcast (cscmdCanvasHidden, NULL);
  918. }
  919. }
  920. return TRUE;
  921. }
  922. case WM_SHOWWINDOW:
  923. {
  924. if (GLOBAL_ASSISTANT != 0)
  925. {
  926. if (wParam)
  927. {
  928. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  929. outlet->Broadcast (cscmdCanvasExposed, NULL);
  930. }
  931. else
  932. {
  933. iEventOutlet* outlet = GLOBAL_ASSISTANT->GetEventOutlet();
  934. outlet->Broadcast (cscmdCanvasHidden, NULL);
  935. }
  936. }
  937. break;
  938. }
  939. }
  940. return DefWindowProc (hWnd, message, wParam, lParam);
  941. }
  942. bool Win32Assistant::SetCursor (int cursor)
  943. {
  944. char *CursorID;
  945. switch (cursor)
  946. {
  947. case csmcNone: CursorID = (char *)-1; break;
  948. case csmcArrow: CursorID = IDC_ARROW; break;
  949. case csmcCross: CursorID = IDC_CROSS; break;
  950. //case csmcPen: CursorID = IDC_PEN; break;
  951. case csmcPen: CursorID = MAKEINTRESOURCE(32631); break;
  952. case csmcMove: CursorID = IDC_SIZEALL; break;
  953. case csmcSizeNWSE: CursorID = IDC_SIZENWSE; break;
  954. case csmcSizeNESW: CursorID = IDC_SIZENESW; break;
  955. case csmcSizeNS: CursorID = IDC_SIZENS; break;
  956. case csmcSizeEW: CursorID = IDC_SIZEWE; break;
  957. case csmcStop: CursorID = IDC_NO; break;
  958. case csmcWait: CursorID = IDC_WAIT; break;
  959. default: CursorID = 0; break;
  960. }
  961. bool success;
  962. HCURSOR cur;
  963. if (CursorID)
  964. {
  965. cur = ((CursorID != (char *)-1) ? LoadCursor (NULL, CursorID) : NULL);
  966. success = true;
  967. }
  968. else
  969. {
  970. cur = NULL;
  971. success = false;
  972. }
  973. SetWinCursor (cur);
  974. return success;
  975. }
  976. void Win32Assistant::DisableConsole ()
  977. {
  978. if (console_window)
  979. {
  980. console_window = false;
  981. }
  982. char apppath[MAX_PATH];
  983. GetModuleFileName (0, apppath, sizeof(apppath));
  984. char *dot = strrchr (apppath, '.');
  985. if (dot)
  986. {
  987. strcpy (dot, ".txt");
  988. }
  989. else
  990. {
  991. strcat (apppath, ".txt");
  992. }
  993. freopen(apppath, "a", stderr);
  994. freopen(apppath, "a", stdout);
  995. FreeConsole();
  996. struct tm *now;
  997. time_t aclock;
  998. time( &aclock );
  999. now = localtime( &aclock );
  1000. printf("====== %s", asctime(now));
  1001. }
  1002. void Win32Assistant::AlertV (HWND window, int type, const char* title,
  1003. const char* okMsg, const char* msg, va_list args)
  1004. {
  1005. UINT style = MB_OK;
  1006. if (type == CS_ALERT_ERROR)
  1007. style |= MB_ICONERROR;
  1008. else if (type == CS_ALERT_WARNING)
  1009. style |= MB_ICONWARNING;
  1010. else if (type == CS_ALERT_NOTE)
  1011. style |= MB_ICONINFORMATION;
  1012. char buf[4096];
  1013. vsprintf(buf, msg, args);
  1014. MessageBox (window, buf, title, style);
  1015. }
  1016. //@@@ somewhat ugly.
  1017. extern int _cs_main (int argc, char* argv[]);
  1018. #undef main
  1019. int main (int argc, char* argv[])
  1020. {
  1021. CS_DEBUG_MSVC_INIT_GOOP;
  1022. int ret = _cs_main(argc, argv);
  1023. CS_DEBUG_MSVC_EXIT_GOOP;
  1024. return ret;
  1025. }