curses 1.2.6 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (253) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +19 -0
  3. data/.github/workflows/ubuntu.yml +26 -0
  4. data/.github/workflows/windows.yml +28 -0
  5. data/.gitmodules +1 -1
  6. data/.travis.yml +6 -3
  7. data/History.md +40 -0
  8. data/README.md +4 -1
  9. data/Rakefile +0 -83
  10. data/curses.gemspec +2 -3
  11. data/ext/curses/curses.c +1271 -151
  12. data/ext/curses/extconf.rb +140 -17
  13. data/lib/curses.rb +5 -12
  14. data/sample/form.rb +52 -0
  15. data/sample/menu.rb +1 -1
  16. data/vendor/PDCurses/.gitignore +47 -0
  17. data/vendor/PDCurses/.travis.yml +49 -0
  18. data/vendor/PDCurses/CMakeLists.txt +68 -0
  19. data/vendor/PDCurses/HISTORY.md +2036 -0
  20. data/vendor/PDCurses/IMPLEMNT.md +327 -0
  21. data/vendor/PDCurses/README.md +77 -0
  22. data/vendor/PDCurses/acs_defs.h +265 -0
  23. data/vendor/PDCurses/appveyor.yml +218 -0
  24. data/vendor/PDCurses/cmake/README.md +71 -0
  25. data/vendor/PDCurses/cmake/build_dependencies.cmake +178 -0
  26. data/vendor/PDCurses/cmake/build_options.cmake +25 -0
  27. data/vendor/PDCurses/cmake/dll_version.cmake +26 -0
  28. data/vendor/PDCurses/cmake/gen_config_header.cmake +43 -0
  29. data/vendor/PDCurses/cmake/get_version.cmake +17 -0
  30. data/vendor/PDCurses/cmake/make_uninstall.cmake +19 -0
  31. data/vendor/PDCurses/cmake/project_common.cmake +121 -0
  32. data/vendor/PDCurses/cmake/resource.in.cmake +52 -0
  33. data/vendor/PDCurses/cmake/sdl2_ttf/CMakeLists.txt +83 -0
  34. data/vendor/PDCurses/cmake/target_arch.cmake +36 -0
  35. data/vendor/PDCurses/cmake/version.in.cmake +73 -0
  36. data/vendor/PDCurses/cmake/watcom_open_dos16_toolchain.cmake +96 -0
  37. data/vendor/PDCurses/cmake/watcom_open_dos32_toolchain.cmake +106 -0
  38. data/vendor/PDCurses/cmake/watcom_open_os2v2_toolchain.cmake +105 -0
  39. data/vendor/PDCurses/curses.h +1846 -0
  40. data/vendor/PDCurses/curspriv.h +134 -0
  41. data/vendor/PDCurses/demos/README.md +25 -0
  42. data/vendor/PDCurses/demos/firework.c +144 -0
  43. data/vendor/PDCurses/demos/newtest.c +581 -0
  44. data/vendor/PDCurses/demos/ozdemo.c +447 -0
  45. data/vendor/PDCurses/demos/ptest.c +283 -0
  46. data/vendor/PDCurses/demos/rain.c +157 -0
  47. data/vendor/PDCurses/demos/testcurs.c +1607 -0
  48. data/vendor/PDCurses/demos/tui.c +1048 -0
  49. data/vendor/PDCurses/demos/tui.h +65 -0
  50. data/vendor/PDCurses/demos/tuidemo.c +233 -0
  51. data/vendor/PDCurses/demos/version.c +61 -0
  52. data/vendor/PDCurses/demos/worm.c +432 -0
  53. data/vendor/PDCurses/demos/xmas.c +955 -0
  54. data/vendor/PDCurses/dos/CMakeLists.txt +47 -0
  55. data/vendor/PDCurses/dos/Makefile.bcc +83 -0
  56. data/vendor/PDCurses/dos/Makefile.dmc +257 -0
  57. data/vendor/PDCurses/dos/Makefile.msc +113 -0
  58. data/vendor/PDCurses/dos/Makefile.wcc +107 -0
  59. data/vendor/PDCurses/dos/README.md +51 -0
  60. data/vendor/PDCurses/dos/bccdos.lrf +9 -0
  61. data/vendor/PDCurses/dos/mscdos.lrf +50 -0
  62. data/vendor/PDCurses/dos/pdcclip.c +132 -0
  63. data/vendor/PDCurses/dos/pdcdisp.c +135 -0
  64. data/vendor/PDCurses/dos/pdcdos.h +194 -0
  65. data/vendor/PDCurses/dos/pdcgetsc.c +98 -0
  66. data/vendor/PDCurses/dos/pdckbd.c +513 -0
  67. data/vendor/PDCurses/dos/pdcscrn.c +785 -0
  68. data/vendor/PDCurses/dos/pdcsetsc.c +101 -0
  69. data/vendor/PDCurses/dos/pdcutil.c +212 -0
  70. data/vendor/PDCurses/libobjs.mif +26 -0
  71. data/vendor/PDCurses/makedist.mif +20 -0
  72. data/vendor/PDCurses/man/README.md +21 -0
  73. data/vendor/PDCurses/man/intro.md +361 -0
  74. data/vendor/PDCurses/man/manext.c +119 -0
  75. data/vendor/PDCurses/man/sdl.md +152 -0
  76. data/vendor/PDCurses/man/sdl2.md +58 -0
  77. data/vendor/PDCurses/man/x11.md +407 -0
  78. data/vendor/PDCurses/ncurses/CMakeLists.txt +66 -0
  79. data/vendor/PDCurses/ncurses/README.md +26 -0
  80. data/vendor/PDCurses/ncurses/makefile +29 -0
  81. data/vendor/PDCurses/os2/CMakeLists.txt +41 -0
  82. data/vendor/PDCurses/os2/Makefile.bcc +90 -0
  83. data/vendor/PDCurses/os2/Makefile.wcc +43 -0
  84. data/vendor/PDCurses/os2/README.md +43 -0
  85. data/vendor/PDCurses/os2/iccos2.lrf +50 -0
  86. data/vendor/PDCurses/os2/iccos2.mak +256 -0
  87. data/vendor/PDCurses/os2/pdcclip.c +188 -0
  88. data/vendor/PDCurses/os2/pdcdisp.c +93 -0
  89. data/vendor/PDCurses/os2/pdcgetsc.c +89 -0
  90. data/vendor/PDCurses/os2/pdckbd.c +521 -0
  91. data/vendor/PDCurses/os2/pdcos2.h +55 -0
  92. data/vendor/PDCurses/os2/pdcscrn.c +449 -0
  93. data/vendor/PDCurses/os2/pdcsetsc.c +112 -0
  94. data/vendor/PDCurses/os2/pdcutil.c +52 -0
  95. data/vendor/PDCurses/panel.h +56 -0
  96. data/vendor/PDCurses/pdcurses/README.md +25 -0
  97. data/vendor/PDCurses/pdcurses/addch.c +693 -0
  98. data/vendor/PDCurses/pdcurses/addchstr.c +245 -0
  99. data/vendor/PDCurses/pdcurses/addstr.c +240 -0
  100. data/vendor/PDCurses/pdcurses/attr.c +359 -0
  101. data/vendor/PDCurses/pdcurses/beep.c +68 -0
  102. data/vendor/PDCurses/pdcurses/bkgd.c +223 -0
  103. data/vendor/PDCurses/pdcurses/border.c +411 -0
  104. data/vendor/PDCurses/pdcurses/clear.c +159 -0
  105. data/vendor/PDCurses/pdcurses/color.c +298 -0
  106. data/vendor/PDCurses/pdcurses/debug.c +109 -0
  107. data/vendor/PDCurses/pdcurses/delch.c +96 -0
  108. data/vendor/PDCurses/pdcurses/deleteln.c +211 -0
  109. data/vendor/PDCurses/pdcurses/deprec.c +27 -0
  110. data/vendor/PDCurses/pdcurses/getch.c +417 -0
  111. data/vendor/PDCurses/pdcurses/getstr.c +474 -0
  112. data/vendor/PDCurses/pdcurses/getyx.c +139 -0
  113. data/vendor/PDCurses/pdcurses/inch.c +127 -0
  114. data/vendor/PDCurses/pdcurses/inchstr.c +214 -0
  115. data/vendor/PDCurses/pdcurses/initscr.c +367 -0
  116. data/vendor/PDCurses/pdcurses/inopts.c +324 -0
  117. data/vendor/PDCurses/pdcurses/insch.c +271 -0
  118. data/vendor/PDCurses/pdcurses/insstr.c +264 -0
  119. data/vendor/PDCurses/pdcurses/instr.c +246 -0
  120. data/vendor/PDCurses/pdcurses/kernel.c +259 -0
  121. data/vendor/PDCurses/pdcurses/keyname.c +157 -0
  122. data/vendor/PDCurses/pdcurses/mouse.c +438 -0
  123. data/vendor/PDCurses/pdcurses/move.c +57 -0
  124. data/vendor/PDCurses/pdcurses/outopts.c +159 -0
  125. data/vendor/PDCurses/pdcurses/overlay.c +214 -0
  126. data/vendor/PDCurses/pdcurses/pad.c +260 -0
  127. data/vendor/PDCurses/pdcurses/panel.c +633 -0
  128. data/vendor/PDCurses/pdcurses/printw.c +126 -0
  129. data/vendor/PDCurses/pdcurses/refresh.c +279 -0
  130. data/vendor/PDCurses/pdcurses/scanw.c +578 -0
  131. data/vendor/PDCurses/pdcurses/scr_dump.c +213 -0
  132. data/vendor/PDCurses/pdcurses/scroll.c +101 -0
  133. data/vendor/PDCurses/pdcurses/slk.c +591 -0
  134. data/vendor/PDCurses/pdcurses/termattr.c +182 -0
  135. data/vendor/PDCurses/pdcurses/terminfo.c +217 -0
  136. data/vendor/PDCurses/pdcurses/touch.c +163 -0
  137. data/vendor/PDCurses/pdcurses/util.c +312 -0
  138. data/vendor/PDCurses/pdcurses/window.c +569 -0
  139. data/vendor/PDCurses/sdl1/Makefile.mng +110 -0
  140. data/vendor/PDCurses/sdl1/README.md +31 -0
  141. data/vendor/PDCurses/sdl1/deffont.h +385 -0
  142. data/vendor/PDCurses/sdl1/deficon.h +23 -0
  143. data/vendor/PDCurses/sdl1/pdcclip.c +131 -0
  144. data/vendor/PDCurses/sdl1/pdcdisp.c +373 -0
  145. data/vendor/PDCurses/sdl1/pdcgetsc.c +30 -0
  146. data/vendor/PDCurses/sdl1/pdckbd.c +405 -0
  147. data/vendor/PDCurses/sdl1/pdcscrn.c +414 -0
  148. data/vendor/PDCurses/sdl1/pdcsdl.h +31 -0
  149. data/vendor/PDCurses/sdl1/pdcsetsc.c +64 -0
  150. data/vendor/PDCurses/sdl1/pdcutil.c +40 -0
  151. data/vendor/PDCurses/sdl1/sdltest.c +79 -0
  152. data/vendor/PDCurses/sdl2/CMakeLists.txt +76 -0
  153. data/vendor/PDCurses/sdl2/Makefile.vc +164 -0
  154. data/vendor/PDCurses/sdl2/README.md +34 -0
  155. data/vendor/PDCurses/sdl2/deffont.h +385 -0
  156. data/vendor/PDCurses/sdl2/deficon.h +23 -0
  157. data/vendor/PDCurses/sdl2/pdcclip.c +93 -0
  158. data/vendor/PDCurses/sdl2/pdcdisp.c +534 -0
  159. data/vendor/PDCurses/sdl2/pdcgetsc.c +30 -0
  160. data/vendor/PDCurses/sdl2/pdckbd.c +480 -0
  161. data/vendor/PDCurses/sdl2/pdcscrn.c +443 -0
  162. data/vendor/PDCurses/sdl2/pdcsdl.h +33 -0
  163. data/vendor/PDCurses/sdl2/pdcsetsc.c +67 -0
  164. data/vendor/PDCurses/sdl2/pdcutil.c +39 -0
  165. data/vendor/PDCurses/sdl2/sdltest.c +81 -0
  166. data/vendor/PDCurses/term.h +48 -0
  167. data/vendor/PDCurses/version.mif +7 -0
  168. data/vendor/PDCurses/vt/CMakeLists.txt +28 -0
  169. data/vendor/PDCurses/vt/Makefile.bcc +111 -0
  170. data/vendor/PDCurses/vt/Makefile.dmc +258 -0
  171. data/vendor/PDCurses/vt/Makefile.vc +144 -0
  172. data/vendor/PDCurses/vt/Makefile.wcc +107 -0
  173. data/vendor/PDCurses/vt/README.md +64 -0
  174. data/vendor/PDCurses/vt/pdcclip.c +20 -0
  175. data/vendor/PDCurses/vt/pdcdisp.c +284 -0
  176. data/vendor/PDCurses/vt/pdcgetsc.c +27 -0
  177. data/vendor/PDCurses/vt/pdckbd.c +394 -0
  178. data/vendor/PDCurses/vt/pdcscrn.c +434 -0
  179. data/vendor/PDCurses/vt/pdcsetsc.c +45 -0
  180. data/vendor/PDCurses/vt/pdcutil.c +43 -0
  181. data/vendor/PDCurses/vt/pdcvt.h +16 -0
  182. data/vendor/PDCurses/watcom.mif +68 -0
  183. data/vendor/PDCurses/wincon/CMakeLists.txt +27 -0
  184. data/vendor/PDCurses/wincon/Makefile.bcc +88 -0
  185. data/vendor/PDCurses/wincon/Makefile.dmc +256 -0
  186. data/vendor/PDCurses/wincon/Makefile.lcc +273 -0
  187. data/vendor/PDCurses/wincon/Makefile.mng +176 -0
  188. data/vendor/PDCurses/wincon/Makefile.vc +144 -0
  189. data/vendor/PDCurses/wincon/Makefile.wcc +51 -0
  190. data/vendor/PDCurses/wincon/README.md +85 -0
  191. data/vendor/PDCurses/wincon/pdcclip.c +174 -0
  192. data/vendor/PDCurses/wincon/pdcdisp.c +143 -0
  193. data/vendor/PDCurses/wincon/pdcgetsc.c +55 -0
  194. data/vendor/PDCurses/wincon/pdckbd.c +786 -0
  195. data/vendor/PDCurses/wincon/pdcscrn.c +717 -0
  196. data/vendor/PDCurses/wincon/pdcsetsc.c +91 -0
  197. data/vendor/PDCurses/wincon/pdcurses.ico +0 -0
  198. data/vendor/PDCurses/wincon/pdcurses.rc +28 -0
  199. data/vendor/PDCurses/wincon/pdcutil.c +41 -0
  200. data/vendor/PDCurses/wincon/pdcwin.h +31 -0
  201. data/vendor/PDCurses/wingui/CMakeLists.txt +27 -0
  202. data/vendor/PDCurses/wingui/Makefile.bcc +85 -0
  203. data/vendor/PDCurses/wingui/Makefile.dmc +259 -0
  204. data/vendor/PDCurses/wingui/Makefile.lcc +273 -0
  205. data/vendor/PDCurses/wingui/Makefile.mng +171 -0
  206. data/vendor/PDCurses/wingui/Makefile.vc +144 -0
  207. data/vendor/PDCurses/wingui/Makefile.wcc +51 -0
  208. data/vendor/PDCurses/wingui/README.md +93 -0
  209. data/vendor/PDCurses/wingui/pdcclip.c +174 -0
  210. data/vendor/PDCurses/wingui/pdcdisp.c +718 -0
  211. data/vendor/PDCurses/wingui/pdcgetsc.c +30 -0
  212. data/vendor/PDCurses/wingui/pdckbd.c +143 -0
  213. data/vendor/PDCurses/wingui/pdcscrn.c +2797 -0
  214. data/vendor/PDCurses/wingui/pdcsetsc.c +89 -0
  215. data/vendor/PDCurses/wingui/pdcurses.ico +0 -0
  216. data/vendor/PDCurses/wingui/pdcurses.rc +28 -0
  217. data/vendor/PDCurses/wingui/pdcutil.c +61 -0
  218. data/vendor/PDCurses/wingui/pdcwin.h +122 -0
  219. data/vendor/PDCurses/x11/Makefile.in +754 -0
  220. data/vendor/PDCurses/x11/PDCurses.spec +82 -0
  221. data/vendor/PDCurses/x11/README.md +62 -0
  222. data/vendor/PDCurses/x11/ScrollBox.c +319 -0
  223. data/vendor/PDCurses/x11/ScrollBox.h +51 -0
  224. data/vendor/PDCurses/x11/ScrollBoxP.h +70 -0
  225. data/vendor/PDCurses/x11/aclocal.m4 +994 -0
  226. data/vendor/PDCurses/x11/big_icon.xbm +46 -0
  227. data/vendor/PDCurses/x11/compose.h +201 -0
  228. data/vendor/PDCurses/x11/config.guess +1500 -0
  229. data/vendor/PDCurses/x11/config.h.in +100 -0
  230. data/vendor/PDCurses/x11/config.sub +1616 -0
  231. data/vendor/PDCurses/x11/configure +6700 -0
  232. data/vendor/PDCurses/x11/configure.ac +295 -0
  233. data/vendor/PDCurses/x11/debian/changelog +6 -0
  234. data/vendor/PDCurses/x11/debian/compat +1 -0
  235. data/vendor/PDCurses/x11/debian/control +11 -0
  236. data/vendor/PDCurses/x11/debian/copyright +27 -0
  237. data/vendor/PDCurses/x11/debian/rules +98 -0
  238. data/vendor/PDCurses/x11/install-sh +253 -0
  239. data/vendor/PDCurses/x11/little_icon.xbm +14 -0
  240. data/vendor/PDCurses/x11/ncurses_cfg.h +45 -0
  241. data/vendor/PDCurses/x11/pdcclip.c +173 -0
  242. data/vendor/PDCurses/x11/pdcdisp.c +85 -0
  243. data/vendor/PDCurses/x11/pdcgetsc.c +28 -0
  244. data/vendor/PDCurses/x11/pdckbd.c +104 -0
  245. data/vendor/PDCurses/x11/pdcscrn.c +258 -0
  246. data/vendor/PDCurses/x11/pdcsetsc.c +95 -0
  247. data/vendor/PDCurses/x11/pdcutil.c +52 -0
  248. data/vendor/PDCurses/x11/pdcx11.c +316 -0
  249. data/vendor/PDCurses/x11/pdcx11.h +191 -0
  250. data/vendor/PDCurses/x11/sb.c +155 -0
  251. data/vendor/PDCurses/x11/x11.c +3686 -0
  252. data/vendor/PDCurses/x11/xcurses-config.in +81 -0
  253. metadata +255 -21
@@ -0,0 +1,30 @@
1
+ /* Public Domain Curses */
2
+
3
+ #include "pdcwin.h"
4
+
5
+ /* get the cursor size/shape */
6
+
7
+ int PDC_get_cursor_mode(void)
8
+ {
9
+ PDC_LOG(("PDC_get_cursor_mode() - called\n"));
10
+
11
+ return SP->visibility;
12
+ }
13
+
14
+ /* return number of screen rows */
15
+
16
+ int PDC_get_rows(void)
17
+ {
18
+ extern int PDC_n_rows;
19
+
20
+ PDC_LOG(("PDC_get_rows() - called\n"));
21
+ return( PDC_n_rows);
22
+ }
23
+
24
+ int PDC_get_columns(void)
25
+ {
26
+ extern int PDC_n_cols;
27
+
28
+ PDC_LOG(("PDC_get_columns() - called\n"));
29
+ return( PDC_n_cols);
30
+ }
@@ -0,0 +1,143 @@
1
+ /* Public Domain Curses */
2
+
3
+ #include "pdcwin.h"
4
+ #include <tchar.h>
5
+
6
+ /*man-start**************************************************************
7
+
8
+ Name: pdckbd
9
+
10
+ Synopsis:
11
+ unsigned long PDC_get_input_fd(void);
12
+
13
+ Description:
14
+ PDC_get_input_fd() returns the file descriptor that PDCurses
15
+ reads its input from. It can be used for select(). (For the
16
+ WinGUI version, it's meaningless and returns zero.)
17
+
18
+ Portability X/Open BSD SYS V
19
+ PDC_get_input_fd - - -
20
+
21
+ **man-end****************************************************************/
22
+
23
+
24
+ unsigned long PDC_get_input_fd(void)
25
+ {
26
+ PDC_LOG(("PDC_get_input_fd() - called\n"));
27
+
28
+ return 0L;
29
+ }
30
+
31
+ void PDC_set_keyboard_binary(bool on)
32
+ {
33
+ PDC_LOG(("PDC_set_keyboard_binary() - called\n"));
34
+ }
35
+
36
+ /* check if a key or mouse event is waiting */
37
+
38
+ #define KEY_QUEUE_SIZE 30
39
+
40
+ extern int PDC_key_queue_low, PDC_key_queue_high;
41
+ extern int PDC_key_queue[KEY_QUEUE_SIZE];
42
+ static TCHAR *clipboard_contents;
43
+ static long clipboard_len;
44
+
45
+ int PDC_getclipboard_handle( HANDLE *handle); /* pdcclip.c */
46
+
47
+ /* When copying the clipboard contents for use in the key */
48
+ /* queue, we leave out the line feeds. We also don't do */
49
+ /* it at all if 'clipboard_contents' is already full. */
50
+ void PDC_add_clipboard_to_key_queue( void)
51
+ {
52
+ long i, j;
53
+ HANDLE handle;
54
+
55
+ if( !clipboard_contents)
56
+ if( PDC_getclipboard_handle( &handle) == PDC_CLIP_SUCCESS)
57
+ {
58
+ #ifdef PDC_WIDE
59
+ const long len = (long)wcslen((wchar_t *)handle);
60
+ #else
61
+ const long len = (long)strlen((char *)handle);
62
+ #endif
63
+
64
+ clipboard_contents = (TCHAR *)calloc( len + 1, sizeof( TCHAR));
65
+ memcpy( clipboard_contents, (TCHAR *)handle, (len + 1) * sizeof( TCHAR));
66
+ CloseClipboard( );
67
+ for( i = j = 0; i < len; i++)
68
+ if( clipboard_contents[i] != 10)
69
+ clipboard_contents[j++] = clipboard_contents[i];
70
+ clipboard_len = j;
71
+ }
72
+ }
73
+
74
+ /* PDCurses message/event callback */
75
+ /* Calling PDC_napms for one millisecond ensures that the message loop */
76
+ /* is called and messages in general, and keyboard events in particular, */
77
+ /* get processed. */
78
+
79
+ bool PDC_check_key(void)
80
+ {
81
+ PDC_napms( 1);
82
+ if( PDC_key_queue_low != PDC_key_queue_high || clipboard_len)
83
+ return TRUE;
84
+ return FALSE;
85
+ }
86
+
87
+ /* return the next available key or mouse event */
88
+
89
+ int PDC_get_key(void)
90
+ {
91
+ int rval = -1;
92
+
93
+ if( PDC_key_queue_low != PDC_key_queue_high)
94
+ {
95
+ rval = PDC_key_queue[PDC_key_queue_low++];
96
+ if( PDC_key_queue_low == KEY_QUEUE_SIZE)
97
+ PDC_key_queue_low = 0;
98
+ }
99
+ else if( clipboard_len)
100
+ {
101
+ rval = *clipboard_contents;
102
+ clipboard_len--;
103
+ memmove( clipboard_contents, clipboard_contents + 1, clipboard_len * sizeof( TCHAR));
104
+ if( !clipboard_len)
105
+ {
106
+ free( clipboard_contents);
107
+ clipboard_contents = NULL;
108
+ }
109
+ }
110
+
111
+ SP->key_code = (rval >= KEY_MIN && rval <= KEY_MAX);
112
+ return rval;
113
+ }
114
+
115
+ /* discard any pending keyboard or mouse input -- this is the core
116
+ routine for flushinp() */
117
+
118
+ void PDC_flushinp(void)
119
+ {
120
+ PDC_LOG(("PDC_flushinp() - called\n"));
121
+ PDC_key_queue_low = PDC_key_queue_high = 0;
122
+ if( clipboard_len)
123
+ {
124
+ free( clipboard_contents);
125
+ clipboard_contents = NULL;
126
+ clipboard_len = 0;
127
+ }
128
+ }
129
+
130
+ int PDC_mouse_set(void)
131
+ {
132
+ /* If turning on mouse input: Set ENABLE_MOUSE_INPUT, and clear
133
+ all other flags, including the extended flags;
134
+ If turning off the mouse: Set QuickEdit Mode to the status it
135
+ had on startup, and clear all other flags */
136
+
137
+ return OK;
138
+ }
139
+
140
+ int PDC_modifiers_set(void)
141
+ {
142
+ return OK;
143
+ }
@@ -0,0 +1,2797 @@
1
+ /* Public Domain Curses */
2
+
3
+ #include "pdcwin.h"
4
+ #include <tchar.h>
5
+ #include <stdint.h>
6
+ #include <assert.h>
7
+
8
+ /* COLOR_PAIR to attribute encoding table. */
9
+
10
+ static short *color_pair_indices = (short *)NULL;
11
+ COLORREF *pdc_rgbs = (COLORREF *)NULL;
12
+ static int menu_shown = 1;
13
+ static int min_lines = 25, max_lines = 25;
14
+ static int min_cols = 80, max_cols = 80;
15
+
16
+ #if defined( CHTYPE_LONG) && CHTYPE_LONG >= 2 && defined( PDC_WIDE)
17
+ #define USING_COMBINING_CHARACTER_SCHEME
18
+ int PDC_expand_combined_characters( const cchar_t c, cchar_t *added); /* addch.c */
19
+ #endif
20
+
21
+ /* Some older versions of Microsoft C/C++ don't understand about
22
+ inlined functions. Until we puzzle out which ones do and which
23
+ don't, we'll just leave "inlined" functions as plain old static
24
+ functions. */
25
+
26
+ #ifdef _MSC_VER
27
+ #define INLINE static
28
+ #else
29
+ #define INLINE static inline
30
+ #endif
31
+
32
+ static int keep_size_within_bounds( int *lines, int *cols);
33
+ INLINE int set_default_sizes_from_registry( const int n_cols, const int n_rows,
34
+ const int xloc, const int yloc, const int menu_shown);
35
+ void PDC_transform_line_given_hdc( const HDC hdc, const int lineno,
36
+ int x, int len, const chtype *srcp);
37
+
38
+ #define N_COLORS 256
39
+
40
+ #ifdef A_OVERLINE
41
+ #define A_ALL_LINES (A_UNDERLINE | A_LEFTLINE | A_RIGHTLINE | A_OVERLINE | A_STRIKEOUT)
42
+ #else
43
+ #define A_ALL_LINES (A_UNDERLINE | A_LEFTLINE | A_RIGHTLINE)
44
+ #endif
45
+
46
+ /* If PDC_MAX_MOUSE_BUTTONS is undefined, it means the user hasn't */
47
+ /* gotten a current 'curses.h' in which five-button mice are supported. */
48
+ /* To handle this gracefully, we'll just fall back to three buttons. */
49
+
50
+ #ifndef PDC_MAX_MOUSE_BUTTONS
51
+ #define PDC_MAX_MOUSE_BUTTONS 3
52
+ #endif
53
+
54
+ #define VERTICAL_WHEEL_EVENT PDC_MAX_MOUSE_BUTTONS
55
+ #define HORIZONTAL_WHEEL_EVENT (PDC_MAX_MOUSE_BUTTONS + 1)
56
+
57
+ unsigned long pdc_key_modifiers = 0L;
58
+ int PDC_show_ctrl_alts = 0;
59
+
60
+ /* RR: Removed statis on next line */
61
+ bool PDC_bDone = FALSE;
62
+ static HWND originally_focussed_window;
63
+
64
+ int debug_printf( const char *format, ...)
65
+ {
66
+ static bool debugging = TRUE;
67
+
68
+ if( debugging)
69
+ {
70
+ const char *output_filename = getenv( "PDC_DEBUG");
71
+
72
+ if( !output_filename)
73
+ debugging = FALSE; /* don't bother trying again */
74
+ else
75
+ {
76
+ FILE *ofile = fopen( output_filename, "a");
77
+
78
+ if( ofile)
79
+ {
80
+ va_list argptr;
81
+ va_start( argptr, format);
82
+ vfprintf( ofile, format, argptr);
83
+ va_end( argptr);
84
+ fclose( ofile);
85
+ }
86
+ else
87
+ {
88
+ printf( "Opening '%s' failed\n", output_filename);
89
+ exit( 0);
90
+ debugging = FALSE; /* don't bother trying again */
91
+ }
92
+ }
93
+ }
94
+ return( 0);
95
+ }
96
+
97
+ HWND PDC_hWnd;
98
+ static int PDC_argc = 0;
99
+ static char **PDC_argv = NULL;
100
+
101
+ static void final_cleanup( void)
102
+ {
103
+ debug_printf( "final_cleanup: SP = %p\n", SP);
104
+ if (SP)
105
+ {
106
+ RECT rect;
107
+
108
+ GetWindowRect( PDC_hWnd, &rect);
109
+ set_default_sizes_from_registry( SP->cols, SP->lines,
110
+ rect.left, rect.top, menu_shown);
111
+ }
112
+ PDC_LOG(( "final_cleanup: freeing fonts\n"));
113
+ PDC_transform_line( 0, 0, 0, NULL); /* free any fonts */
114
+ if( originally_focussed_window)
115
+ SetForegroundWindow( originally_focussed_window);
116
+ if( PDC_argc)
117
+ {
118
+ int i;
119
+
120
+ for( i = 0; i < PDC_argc; i++)
121
+ free( PDC_argv[i]);
122
+ free( PDC_argv);
123
+ PDC_argc = 0;
124
+ PDC_argv = NULL;
125
+ }
126
+ #ifdef USING_COMBINING_CHARACTER_SCHEME
127
+ PDC_expand_combined_characters( 0, NULL); /* free internal buffer */
128
+ #endif
129
+ debug_printf( "reset foreground window\n");
130
+ }
131
+
132
+ void PDC_scr_close(void)
133
+ {
134
+ PDC_LOG(("PDC_scr_close() - called\n"));
135
+ final_cleanup( );
136
+ PDC_bDone = TRUE;
137
+ }
138
+
139
+ /* NOTE that PDC_scr_free( ) is called only from delscreen( ), */
140
+ /* which is rarely called. It appears that most programs simply */
141
+ /* rely on the memory getting freed when the program terminates. */
142
+ /* It seems conceivable to me that we could get into some trouble */
143
+ /* here, if SP is freed and NULLed, but then accessed again, */
144
+ /* possibly within the WinGUI window thread. */
145
+
146
+ void PDC_scr_free(void)
147
+ {
148
+ if (SP)
149
+ free(SP);
150
+ SP = (SCREEN *)NULL;
151
+
152
+ if (color_pair_indices)
153
+ free(color_pair_indices);
154
+ color_pair_indices = (short *)NULL;
155
+
156
+ if (pdc_rgbs)
157
+ free(pdc_rgbs);
158
+ pdc_rgbs = (COLORREF *)NULL;
159
+ }
160
+
161
+ int PDC_choose_a_new_font( void); /* pdcdisp.c */
162
+ void PDC_add_clipboard_to_key_queue( void); /* pdckbd.c */
163
+
164
+ #define KEY_QUEUE_SIZE 30
165
+
166
+ /* By default, the PDC_shutdown_key[] array contains 0 */
167
+ /* (i.e., there's no key that's supposed to be returned for */
168
+ /* exit handling), and 22 = Ctrl-V (i.e., hit Ctrl-V to */
169
+ /* paste text from the clipboard into the key queue); then */
170
+ /* Ctl-= (enlarge font) and Ctl-Minus (decrease font); then */
171
+ /* Ctl-, (select font from dialog). */
172
+
173
+ static int PDC_shutdown_key[PDC_MAX_FUNCTION_KEYS] = { 0, 22, CTL_EQUAL, CTL_MINUS,
174
+ CTL_COMMA };
175
+ int PDC_n_rows, PDC_n_cols;
176
+ int PDC_cxChar, PDC_cyChar, PDC_key_queue_low = 0, PDC_key_queue_high = 0;
177
+ int PDC_key_queue[KEY_QUEUE_SIZE];
178
+
179
+ /* If the following is true, you can enter Unicode values by hitting */
180
+ /* Alt and holding it down while typing the value of the character on */
181
+ /* the numeric keypad (for decimal entry); _or_ you can hit Alt-Padplus */
182
+ /* and then enter a hex value, while holding down the Alt key. In */
183
+ /* either case, when you release the Alt key, the Unicode character */
184
+ /* is added to the queue. For hex entry, 0-9 can come either from */
185
+ /* the numeric keypad or the "usual" keyboard. */
186
+ bool PDC_allow_numpad_unicode = TRUE;
187
+ static int numpad_unicode_value = 0;
188
+
189
+ static void adjust_font_size( const int font_size_change);
190
+
191
+ static void add_key_to_queue( const int new_key)
192
+ {
193
+ const int new_idx = ((PDC_key_queue_high + 1) % KEY_QUEUE_SIZE);
194
+ /* This is usually 10, but is set to 16 if the user */
195
+ /* hits ALT_PADPLUS and is about to enter a hex value: */
196
+ static int unicode_radix = 10;
197
+
198
+ if( PDC_allow_numpad_unicode)
199
+ {
200
+ int digit = -1;
201
+
202
+ if( new_key >= ALT_PAD0 && new_key <= ALT_PAD9)
203
+ digit = new_key - ALT_PAD0;
204
+ /* In hex Unicode entry, you can enter digits on both */
205
+ /* the numeric and "standard" keyboards : */
206
+ if( unicode_radix == 16 && new_key >= ALT_0 && new_key <= ALT_9)
207
+ digit = new_key - ALT_0;
208
+ if( unicode_radix == 16 && new_key >= ALT_A && new_key <= ALT_F)
209
+ digit = new_key - ALT_A + 10;
210
+ if( digit >= 0)
211
+ {
212
+ numpad_unicode_value = numpad_unicode_value * unicode_radix + digit;
213
+ return;
214
+ }
215
+ if( new_key == ALT_PADPLUS)
216
+ { /* signal to begin hex Unicode entry */
217
+ unicode_radix = 16;
218
+ return;
219
+ }
220
+ }
221
+ unicode_radix = 10;
222
+ if( new_key && new_key == PDC_shutdown_key[FUNCTION_KEY_PASTE])
223
+ PDC_add_clipboard_to_key_queue( );
224
+ else if( new_key && new_key == PDC_shutdown_key[FUNCTION_KEY_ABORT])
225
+ exit( -1);
226
+ else if( new_key && new_key == PDC_shutdown_key[FUNCTION_KEY_ENLARGE_FONT])
227
+ adjust_font_size( 1);
228
+ else if( new_key && new_key == PDC_shutdown_key[FUNCTION_KEY_SHRINK_FONT])
229
+ adjust_font_size( -1);
230
+ else if( new_key && new_key == PDC_shutdown_key[FUNCTION_KEY_CHOOSE_FONT])
231
+ {
232
+ if( PDC_choose_a_new_font( ))
233
+ adjust_font_size( 0);
234
+ }
235
+ else if( new_idx != PDC_key_queue_low)
236
+ {
237
+ PDC_key_queue[PDC_key_queue_high] = new_key;
238
+ PDC_key_queue_high = new_idx;
239
+ }
240
+ }
241
+
242
+ /************************************************************************
243
+ * Table for key code translation of function keys in keypad mode *
244
+ * These values are for strict IBM keyboard compatibles only *
245
+ ************************************************************************/
246
+
247
+ typedef struct
248
+ {
249
+ unsigned short normal;
250
+ unsigned short shift;
251
+ unsigned short control;
252
+ unsigned short alt;
253
+ unsigned short extended;
254
+ } KPTAB;
255
+
256
+
257
+ static const KPTAB kptab[] =
258
+ {
259
+ {0, 0, 0, 0, 0 }, /* 0 */
260
+ {0, 0, 0, 0, 0 }, /* 1 VK_LBUTTON */
261
+ {0, 0, 0, 0, 0 }, /* 2 VK_RBUTTON */
262
+ {CTL_PAUSE, 'a', 'b', 'c', 0 }, /* 3 VK_CANCEL */
263
+ {0, 0, 0, 0, 0 }, /* 4 VK_MBUTTON */
264
+ {0, 0, 0, 0, 0 }, /* 5 */
265
+ {0, 0, 0, 0, 0 }, /* 6 */
266
+ {0, 0, 0, 0, 0 }, /* 7 */
267
+ {0x08, 0x08, 0x7F, ALT_BKSP, 0 }, /* 8 VK_BACK */
268
+ {0x09, KEY_BTAB, CTL_TAB, ALT_TAB, 999 }, /* 9 VK_TAB */
269
+ {0, 0, 0, 0, 0 }, /* 10 */
270
+ {0, 0, 0, 0, 0 }, /* 11 */
271
+ {KEY_B2, 0x35, CTL_PAD5, ALT_PAD5, 0 }, /* 12 VK_CLEAR */
272
+ {0x0D, 0x0D, CTL_ENTER, ALT_ENTER, 1 }, /* 13 VK_RETURN */
273
+ {0, 0, 0, 0, 0 }, /* 14 */
274
+ {0, 0, 0, 0, 0 }, /* 15 */
275
+ {0, 0, 0, 0, 0 }, /* 16 VK_SHIFT HANDLED SEPARATELY */
276
+ {0, 0, 0, 0, 0 }, /* 17 VK_CONTROL HANDLED SEPARATELY */
277
+ {0, 0, 0, 0, 0 }, /* 18 VK_MENU HANDLED SEPARATELY */
278
+ {KEY_PAUSE, KEY_SPAUSE,CTL_PAUSE, 0, 0 }, /* 19 VK_PAUSE */
279
+ {0, 0, 0, 0, 0 }, /* 20 VK_CAPITAL HANDLED SEPARATELY */
280
+ {0, 0, 0, 0, 0 }, /* 21 VK_HANGUL */
281
+ {0, 0, 0, 0, 0 }, /* 22 */
282
+ {0, 0, 0, 0, 0 }, /* 23 VK_JUNJA */
283
+ {0, 0, 0, 0, 0 }, /* 24 VK_FINAL */
284
+ {0, 0, 0, 0, 0 }, /* 25 VK_HANJA */
285
+ {0, 0, 0, 0, 0 }, /* 26 */
286
+ {0x1B, 0x1B, 0x1B, ALT_ESC, 0 }, /* 27 VK_ESCAPE */
287
+ {0, 0, 0, 0, 0 }, /* 28 VK_CONVERT */
288
+ {0, 0, 0, 0, 0 }, /* 29 VK_NONCONVERT */
289
+ {0, 0, 0, 0, 0 }, /* 30 VK_ACCEPT */
290
+ {0, 0, 0, 0, 0 }, /* 31 VK_MODECHANGE */
291
+ {0x20, 0x20, 0x20, 0x20, 0 }, /* 32 VK_SPACE */
292
+ {KEY_A3, 0x39, CTL_PAD9, ALT_PAD9, 3 }, /* 33 VK_PRIOR */
293
+ {KEY_C3, 0x33, CTL_PAD3, ALT_PAD3, 4 }, /* 34 VK_NEXT */
294
+ {KEY_C1, 0x31, CTL_PAD1, ALT_PAD1, 5 }, /* 35 VK_END */
295
+ {KEY_A1, 0x37, CTL_PAD7, ALT_PAD7, 6 }, /* 36 VK_HOME */
296
+ {KEY_B1, 0x34, CTL_PAD4, ALT_PAD4, 7 }, /* 37 VK_LEFT */
297
+ {KEY_A2, 0x38, CTL_PAD8, ALT_PAD8, 8 }, /* 38 VK_UP */
298
+ {KEY_B3, 0x36, CTL_PAD6, ALT_PAD6, 9 }, /* 39 VK_RIGHT */
299
+ {KEY_C2, 0x32, CTL_PAD2, ALT_PAD2, 10 }, /* 40 VK_DOWN */
300
+ {0, 0, 0, 0, 0 }, /* 41 VK_SELECT */
301
+ {0, 0, 0, 0, 0 }, /* 42 VK_PRINT */
302
+ {0, 0, 0, 0, 0 }, /* 43 VK_EXECUTE */
303
+ {KEY_PRINTSCREEN, 0, 0, ALT_PRINTSCREEN, 0 }, /* 44 VK_SNAPSHOT*/
304
+ {PAD0, 0x30, CTL_PAD0, ALT_PAD0, 11 }, /* 45 VK_INSERT */
305
+ {PADSTOP, 0x2E, CTL_PADSTOP, ALT_PADSTOP,12 }, /* 46 VK_DELETE */
306
+ {0, 0, 0, 0, 0 }, /* 47 VK_HELP */
307
+ {0x30, 0x29, CTL_0, ALT_0, 0 }, /* 48 */
308
+ {0x31, 0x21, CTL_1, ALT_1, 0 }, /* 49 */
309
+ {0x32, 0x40, CTL_2, ALT_2, 0 }, /* 50 */
310
+ {0x33, 0x23, CTL_3, ALT_3, 0 }, /* 51 */
311
+ {0x34, 0x24, CTL_4, ALT_4, 0 }, /* 52 */
312
+ {0x35, 0x25, CTL_5, ALT_5, 0 }, /* 53 */
313
+ {0x36, 0x5E, CTL_6, ALT_6, 0 }, /* 54 */
314
+ {0x37, 0x26, CTL_7, ALT_7, 0 }, /* 55 */
315
+ {0x38, 0x2A, CTL_8, ALT_8, 0 }, /* 56 */
316
+ {0x39, 0x28, CTL_9, ALT_9, 0 }, /* 57 */
317
+ {0, 0, 0, 0, 0 }, /* 58 */
318
+ {0, 0, 0, 0, 0 }, /* 59 */
319
+ {0, 0, 0, 0, 0 }, /* 60 */
320
+ {0, 0, 0, 0, 0 }, /* 61 */
321
+ {0, 0, 0, 0, 0 }, /* 62 */
322
+ {0, 0, 0, 0, 0 }, /* 63 */
323
+ {0, 0, 0, 0, 0 }, /* 64 */
324
+ {0x61, 0x41, 0x01, ALT_A, 0 }, /* 65 */
325
+ {0x62, 0x42, 0x02, ALT_B, 0 }, /* 66 */
326
+ {0x63, 0x43, 0x03, ALT_C, 0 }, /* 67 */
327
+ {0x64, 0x44, 0x04, ALT_D, 0 }, /* 68 */
328
+ {0x65, 0x45, 0x05, ALT_E, 0 }, /* 69 */
329
+ {0x66, 0x46, 0x06, ALT_F, 0 }, /* 70 */
330
+ {0x67, 0x47, 0x07, ALT_G, 0 }, /* 71 */
331
+ {0x68, 0x48, 0x08, ALT_H, 0 }, /* 72 */
332
+ {0x69, 0x49, 0x09, ALT_I, 0 }, /* 73 */
333
+ {0x6A, 0x4A, 0x0A, ALT_J, 0 }, /* 74 */
334
+ {0x6B, 0x4B, 0x0B, ALT_K, 0 }, /* 75 */
335
+ {0x6C, 0x4C, 0x0C, ALT_L, 0 }, /* 76 */
336
+ {0x6D, 0x4D, 0x0D, ALT_M, 0 }, /* 77 */
337
+ {0x6E, 0x4E, 0x0E, ALT_N, 0 }, /* 78 */
338
+ {0x6F, 0x4F, 0x0F, ALT_O, 0 }, /* 79 */
339
+ {0x70, 0x50, 0x10, ALT_P, 0 }, /* 80 */
340
+ {0x71, 0x51, 0x11, ALT_Q, 0 }, /* 81 */
341
+ {0x72, 0x52, 0x12, ALT_R, 0 }, /* 82 */
342
+ {0x73, 0x53, 0x13, ALT_S, 0 }, /* 83 */
343
+ {0x74, 0x54, 0x14, ALT_T, 0 }, /* 84 */
344
+ {0x75, 0x55, 0x15, ALT_U, 0 }, /* 85 */
345
+ {0x76, 0x56, 0x16, ALT_V, 0 }, /* 86 */
346
+ {0x77, 0x57, 0x17, ALT_W, 0 }, /* 87 */
347
+ {0x78, 0x58, 0x18, ALT_X, 0 }, /* 88 */
348
+ {0x79, 0x59, 0x19, ALT_Y, 0 }, /* 89 */
349
+ {0x7A, 0x5A, 0x1A, ALT_Z, 0 }, /* 90 */
350
+ {0, 0, 0, 0, 0 }, /* 91 VK_LWIN */
351
+ {0, 0, 0, 0, 0 }, /* 92 VK_RWIN */
352
+ {KEY_APPS, KEY_SAPPS, CTL_APPS, ALT_APPS, 13 }, /* 93 VK_APPS */
353
+ {0, 0, 0, 0, 0 }, /* 94 */
354
+ {0, 0, 0, 0, 0 }, /* 95 */
355
+ {0x30, 0, CTL_PAD0, ALT_PAD0, 0 }, /* 96 VK_NUMPAD0 */
356
+ {0x31, 0, CTL_PAD1, ALT_PAD1, 0 }, /* 97 VK_NUMPAD1 */
357
+ {0x32, 0, CTL_PAD2, ALT_PAD2, 0 }, /* 98 VK_NUMPAD2 */
358
+ {0x33, 0, CTL_PAD3, ALT_PAD3, 0 }, /* 99 VK_NUMPAD3 */
359
+ {0x34, 0, CTL_PAD4, ALT_PAD4, 0 }, /* 100 VK_NUMPAD4 */
360
+ {0x35, 0, CTL_PAD5, ALT_PAD5, 0 }, /* 101 VK_NUMPAD5 */
361
+ {0x36, 0, CTL_PAD6, ALT_PAD6, 0 }, /* 102 VK_NUMPAD6 */
362
+ {0x37, 0, CTL_PAD7, ALT_PAD7, 0 }, /* 103 VK_NUMPAD7 */
363
+ {0x38, 0, CTL_PAD8, ALT_PAD8, 0 }, /* 104 VK_NUMPAD8 */
364
+ {0x39, 0, CTL_PAD9, ALT_PAD9, 0 }, /* 105 VK_NUMPAD9 */
365
+ {PADSTAR, SHF_PADSTAR,CTL_PADSTAR, ALT_PADSTAR,999 }, /* 106 VK_MULTIPLY*/
366
+ {PADPLUS, SHF_PADPLUS,CTL_PADPLUS, ALT_PADPLUS,999 }, /* 107 VK_ADD */
367
+ {0, 0, 0, 0, 0 }, /* 108 VK_SEPARATOR */
368
+ {PADMINUS, SHF_PADMINUS,CTL_PADMINUS,ALT_PADMINUS,999}, /* 109 VK_SUBTRACT*/
369
+ {0x2E, 0, CTL_PADSTOP, ALT_PADSTOP,0 }, /* 110 VK_DECIMAL */
370
+ {PADSLASH, SHF_PADSLASH,CTL_PADSLASH,ALT_PADSLASH,2 }, /* 111 VK_DIVIDE */
371
+ {KEY_F(1), KEY_F(13), KEY_F(25), KEY_F(37), 0 }, /* 112 VK_F1 */
372
+ {KEY_F(2), KEY_F(14), KEY_F(26), KEY_F(38), 0 }, /* 113 VK_F2 */
373
+ {KEY_F(3), KEY_F(15), KEY_F(27), KEY_F(39), 0 }, /* 114 VK_F3 */
374
+ {KEY_F(4), KEY_F(16), KEY_F(28), KEY_F(40), 0 }, /* 115 VK_F4 */
375
+ {KEY_F(5), KEY_F(17), KEY_F(29), KEY_F(41), 0 }, /* 116 VK_F5 */
376
+ {KEY_F(6), KEY_F(18), KEY_F(30), KEY_F(42), 0 }, /* 117 VK_F6 */
377
+ {KEY_F(7), KEY_F(19), KEY_F(31), KEY_F(43), 0 }, /* 118 VK_F7 */
378
+ {KEY_F(8), KEY_F(20), KEY_F(32), KEY_F(44), 0 }, /* 119 VK_F8 */
379
+ {KEY_F(9), KEY_F(21), KEY_F(33), KEY_F(45), 0 }, /* 120 VK_F9 */
380
+ {KEY_F(10), KEY_F(22), KEY_F(34), KEY_F(46), 0 }, /* 121 VK_F10 */
381
+ {KEY_F(11), KEY_F(23), KEY_F(35), KEY_F(47), 0 }, /* 122 VK_F11 */
382
+ {KEY_F(12), KEY_F(24), KEY_F(36), KEY_F(48), 0 }, /* 123 VK_F12 */
383
+
384
+ /* 124 through 218 */
385
+
386
+ {0, 0, 0, 0, 0}, /* 124 VK_F13 */
387
+ {0, 0, 0, 0, 0}, /* 125 VK_F14 */
388
+ {0, 0, 0, 0, 0}, /* 126 VK_F15 */
389
+ {0, 0, 0, 0, 0}, /* 127 VK_F16 */
390
+ {0, 0, 0, 0, 0}, /* 128 VK_F17 */
391
+ {0, 0, 0, 0, 0}, /* 129 VK_F18 */
392
+ {0, 0, 0, 0, 0}, /* 130 VK_F19 */
393
+ {0, 0, 0, 0, 0}, /* 131 VK_F20 */
394
+ {0, 0, 0, 0, 0}, /* 132 VK_F21 */
395
+ {0, 0, 0, 0, 0}, /* 133 VK_F22 */
396
+ {0, 0, 0, 0, 0}, /* 134 VK_F23 */
397
+ {0, 0, 0, 0, 0}, /* 135 VK_F24 */
398
+ {0, 0, 0, 0, 0}, /* 136 unassigned */
399
+ {0, 0, 0, 0, 0}, /* 137 unassigned */
400
+ {0, 0, 0, 0, 0}, /* 138 unassigned */
401
+ {0, 0, 0, 0, 0}, /* 139 unassigned */
402
+ {0, 0, 0, 0, 0}, /* 140 unassigned */
403
+ {0, 0, 0, 0, 0}, /* 141 unassigned */
404
+ {0, 0, 0, 0, 0}, /* 142 unassigned */
405
+ {0, 0, 0, 0, 0}, /* 143 unassigned */
406
+ {0, 0, 0, 0, 0}, /* 144 VK_NUMLOCK */
407
+ {KEY_SCROLLLOCK, 0, 0, ALT_SCROLLLOCK, 0}, /* 145 VKSCROLL */
408
+ {0, 0, 0, 0, 0}, /* 146 OEM specific */
409
+ {0, 0, 0, 0, 0}, /* 147 OEM specific */
410
+ {0, 0, 0, 0, 0}, /* 148 OEM specific */
411
+ {0, 0, 0, 0, 0}, /* 149 OEM specific */
412
+ {0, 0, 0, 0, 0}, /* 150 OEM specific */
413
+ {0, 0, 0, 0, 0}, /* 151 Unassigned */
414
+ {0, 0, 0, 0, 0}, /* 152 Unassigned */
415
+ {0, 0, 0, 0, 0}, /* 153 Unassigned */
416
+ {0, 0, 0, 0, 0}, /* 154 Unassigned */
417
+ {0, 0, 0, 0, 0}, /* 155 Unassigned */
418
+ {0, 0, 0, 0, 0}, /* 156 Unassigned */
419
+ {0, 0, 0, 0, 0}, /* 157 Unassigned */
420
+ {0, 0, 0, 0, 0}, /* 158 Unassigned */
421
+ {0, 0, 0, 0, 0}, /* 159 Unassigned */
422
+ {0, 0, 0, 0, 0}, /* 160 VK_LSHIFT */
423
+ {0, 0, 0, 0, 0}, /* 161 VK_RSHIFT */
424
+ {0, 0, 0, 0, 0}, /* 162 VK_LCONTROL */
425
+ {0, 0, 0, 0, 0}, /* 163 VK_RCONTROL */
426
+ {0, 0, 0, 0, 0}, /* 164 VK_LMENU */
427
+ {0, 0, 0, 0, 0}, /* 165 VK_RMENU */
428
+ {0, 0, 0, 0, 14}, /* 166 VK_BROWSER_BACK */
429
+ {0, 0, 0, 0, 15}, /* 167 VK_BROWSER_FORWARD */
430
+ {0, 0, 0, 0, 16}, /* 168 VK_BROWSER_REFRESH */
431
+ {0, 0, 0, 0, 17}, /* 169 VK_BROWSER_STOP */
432
+ {0, 0, 0, 0, 18}, /* 170 VK_BROWSER_SEARCH */
433
+ {0, 0, 0, 0, 19}, /* 171 VK_BROWSER_FAVORITES */
434
+ {0, 0, 0, 0, 20}, /* 172 VK_BROWSER_HOME */
435
+ {0, 0, 0, 0, 21}, /* 173 VK_VOLUME_MUTE */
436
+ {0, 0, 0, 0, 22}, /* 174 VK_VOLUME_DOWN */
437
+ {0, 0, 0, 0, 23}, /* 175 VK_VOLUME_UP */
438
+ {0, 0, 0, 0, 24}, /* 176 VK_MEDIA_NEXT_TRACK */
439
+ {0, 0, 0, 0, 25}, /* 177 VK_MEDIA_PREV_TRACK */
440
+ {0, 0, 0, 0, 26}, /* 178 VK_MEDIA_STOP */
441
+ {0, 0, 0, 0, 27}, /* 179 VK_MEDIA_PLAY_PAUSE */
442
+ {0, 0, 0, 0, 28}, /* 180 VK_LAUNCH_MAIL */
443
+ {0, 0, 0, 0, 29}, /* 181 VK_LAUNCH_MEDIA_SELECT */
444
+ {0, 0, 0, 0, 30}, /* 182 VK_LAUNCH_APP1 */
445
+ {0, 0, 0, 0, 31}, /* 183 VK_LAUNCH_APP2 */
446
+ {0, 0, 0, 0, 0}, /* 184 Reserved */
447
+ {0, 0, 0, 0, 0}, /* 185 Reserved */
448
+ {';', ':', CTL_SEMICOLON, ALT_SEMICOLON, 0}, /* 186 VK_OEM_1 */
449
+ {'=', '+', CTL_EQUAL, ALT_EQUAL, 0}, /* 187 VK_OEM_PLUS */
450
+ {',', '<', CTL_COMMA, ALT_COMMA, 0}, /* 188 VK_OEM_COMMA */
451
+ {'-', '_', CTL_MINUS, ALT_MINUS, 0}, /* 189 VK_OEM_MINUS */
452
+ {'.', '>', CTL_STOP, ALT_STOP, 0}, /* 190 VK_OEM_PERIOD */
453
+ {'/', '?', CTL_FSLASH, ALT_FSLASH, 0}, /* 191 VK_OEM_2 */
454
+ {'`', '~', CTL_BQUOTE, ALT_BQUOTE, 0}, /* 192 VK_OEM_3 */
455
+ {0, 0, 0, 0, 0}, /* 193 */
456
+ {0, 0, 0, 0, 0}, /* 194 */
457
+ {0, 0, 0, 0, 0}, /* 195 */
458
+ {0, 0, 0, 0, 0}, /* 196 */
459
+ {0, 0, 0, 0, 0}, /* 197 */
460
+ {0, 0, 0, 0, 0}, /* 198 */
461
+ {0, 0, 0, 0, 0}, /* 199 */
462
+ {0, 0, 0, 0, 0}, /* 200 */
463
+ {0, 0, 0, 0, 0}, /* 201 */
464
+ {0, 0, 0, 0, 0}, /* 202 */
465
+ {0, 0, 0, 0, 0}, /* 203 */
466
+ {0, 0, 0, 0, 0}, /* 204 */
467
+ {0, 0, 0, 0, 0}, /* 205 */
468
+ {0, 0, 0, 0, 0}, /* 206 */
469
+ {0, 0, 0, 0, 0}, /* 207 */
470
+ {0, 0, 0, 0, 0}, /* 208 */
471
+ {0, 0, 0, 0, 0}, /* 209 */
472
+ {0, 0, 0, 0, 0}, /* 210 */
473
+ {0, 0, 0, 0, 0}, /* 211 */
474
+ {0, 0, 0, 0, 0}, /* 212 */
475
+ {0, 0, 0, 0, 0}, /* 213 */
476
+ {0, 0, 0, 0, 0}, /* 214 */
477
+ {0, 0, 0, 0, 0}, /* 215 */
478
+ {0, 0, 0, 0, 0}, /* 216 */
479
+ {0, 0, 0, 0, 0}, /* 217 */
480
+ {0, 0, 0, 0, 0}, /* 218 */
481
+ {0x5B, 0x7B, 0x1B, ALT_LBRACKET,0 }, /* 219 VK_OEM_4 */
482
+ {0x5C, 0x7C, 0x1C, ALT_BSLASH, 0 }, /* 220 VK_OEM_5 */
483
+ {0x5D, 0x7D, 0x1D, ALT_RBRACKET,0 }, /* 221 VK_OEM_6 */
484
+ {'\'', '"', 0x27, ALT_FQUOTE, 0 }, /* 222 VK_OEM_7 */
485
+ {0, 0, 0, 0, 0 }, /* 223 VK_OEM_8 */
486
+ {0, 0, 0, 0, 0 }, /* 224 */
487
+ {0, 0, 0, 0, 0 } /* 225 */
488
+ };
489
+ /* End of kptab[] */
490
+
491
+ static const KPTAB ext_kptab[] =
492
+ {
493
+ {0, 0, 0, 0, }, /* 0 MUST BE EMPTY */
494
+ {PADENTER, SHF_PADENTER, CTL_PADENTER, ALT_PADENTER}, /* 1 13 */
495
+ {PADSLASH, SHF_PADSLASH, CTL_PADSLASH, ALT_PADSLASH}, /* 2 111 */
496
+ {KEY_PPAGE, KEY_SPREVIOUS, CTL_PGUP, ALT_PGUP }, /* 3 33 */
497
+ {KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN }, /* 4 34 */
498
+ {KEY_END, KEY_SEND, CTL_END, ALT_END }, /* 5 35 */
499
+ {KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME }, /* 6 36 */
500
+ {KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT }, /* 7 37 */
501
+ {KEY_UP, KEY_SUP, CTL_UP, ALT_UP }, /* 8 38 */
502
+ {KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT }, /* 9 39 */
503
+ {KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN }, /* 10 40 */
504
+ {KEY_IC, KEY_SIC, CTL_INS, ALT_INS }, /* 11 45 */
505
+ {KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL }, /* 12 46 */
506
+ {KEY_APPS, KEY_SAPPS , CTL_APPS, ALT_APPS }, /* 13 93 VK_APPS */
507
+ {KEY_BROWSER_BACK, KEY_SBROWSER_BACK, KEY_CBROWSER_BACK, KEY_ABROWSER_BACK, }, /* 14 166 VK_BROWSER_BACK */
508
+ {KEY_BROWSER_FWD, KEY_SBROWSER_FWD, KEY_CBROWSER_FWD, KEY_ABROWSER_FWD, }, /* 15 167 VK_BROWSER_FORWARD */
509
+ {KEY_BROWSER_REF, KEY_SBROWSER_REF, KEY_CBROWSER_REF, KEY_ABROWSER_REF, }, /* 16 168 VK_BROWSER_REFRESH */
510
+ {KEY_BROWSER_STOP, KEY_SBROWSER_STOP, KEY_CBROWSER_STOP, KEY_ABROWSER_STOP, }, /* 17 169 VK_BROWSER_STOP */
511
+ {KEY_SEARCH, KEY_SSEARCH, KEY_CSEARCH, KEY_ASEARCH, }, /* 18 170 VK_BROWSER_SEARCH */
512
+ {KEY_FAVORITES, KEY_SFAVORITES, KEY_CFAVORITES, KEY_AFAVORITES, }, /* 19 171 VK_BROWSER_FAVORITES */
513
+ {KEY_BROWSER_HOME, KEY_SBROWSER_HOME, KEY_CBROWSER_HOME, KEY_ABROWSER_HOME, }, /* 20 172 VK_BROWSER_HOME */
514
+ {KEY_VOLUME_MUTE, KEY_SVOLUME_MUTE, KEY_CVOLUME_MUTE, KEY_AVOLUME_MUTE, }, /* 21 173 VK_VOLUME_MUTE */
515
+ {KEY_VOLUME_DOWN, KEY_SVOLUME_DOWN, KEY_CVOLUME_DOWN, KEY_AVOLUME_DOWN, }, /* 22 174 VK_VOLUME_DOWN */
516
+ {KEY_VOLUME_UP, KEY_SVOLUME_UP, KEY_CVOLUME_UP, KEY_AVOLUME_UP, }, /* 23 175 VK_VOLUME_UP */
517
+ {KEY_NEXT_TRACK, KEY_SNEXT_TRACK, KEY_CNEXT_TRACK, KEY_ANEXT_TRACK, }, /* 24 176 VK_MEDIA_NEXT_TRACK */
518
+ {KEY_PREV_TRACK, KEY_SPREV_TRACK, KEY_CPREV_TRACK, KEY_APREV_TRACK, }, /* 25 177 VK_MEDIA_PREV_TRACK */
519
+ {KEY_MEDIA_STOP, KEY_SMEDIA_STOP, KEY_CMEDIA_STOP, KEY_AMEDIA_STOP, }, /* 26 178 VK_MEDIA_STOP */
520
+ {KEY_PLAY_PAUSE, KEY_SPLAY_PAUSE, KEY_CPLAY_PAUSE, KEY_APLAY_PAUSE, }, /* 27 179 VK_MEDIA_PLAY_PAUSE */
521
+ {KEY_LAUNCH_MAIL, KEY_SLAUNCH_MAIL, KEY_CLAUNCH_MAIL, KEY_ALAUNCH_MAIL, }, /* 28 180 VK_LAUNCH_MAIL */
522
+ {KEY_MEDIA_SELECT, KEY_SMEDIA_SELECT, KEY_CMEDIA_SELECT, KEY_AMEDIA_SELECT, }, /* 29 181 VK_LAUNCH_MEDIA_SELECT */
523
+ {KEY_LAUNCH_APP1, KEY_SLAUNCH_APP1, KEY_CLAUNCH_APP1, KEY_ALAUNCH_APP1, }, /* 30 182 VK_LAUNCH_APP1 */
524
+ {KEY_LAUNCH_APP2, KEY_SLAUNCH_APP2, KEY_CLAUNCH_APP2, KEY_ALAUNCH_APP2, }, /* 31 183 VK_LAUNCH_APP2 */
525
+ };
526
+
527
+
528
+ HFONT PDC_get_font_handle( const int is_bold); /* pdcdisp.c */
529
+
530
+ /* Mouse handling is done as follows:
531
+
532
+ What we want is a setup wherein, if the user presses and releases a
533
+ mouse button within SP->mouse_wait milliseconds, there will be a
534
+ KEY_MOUSE issued through getch( ) and the "button state" for that button
535
+ will be set to BUTTON_CLICKED.
536
+
537
+ If the user presses and releases the button, and it takes _longer_
538
+ than SP->mouse_wait milliseconds, then there should be a KEY_MOUSE
539
+ issued with the "button state" set to BUTTON_PRESSED. Then, later,
540
+ another KEY_MOUSE with a BUTTON_RELEASED.
541
+
542
+ To accomplish this: when a message such as WM_LBUTTONDOWN,
543
+ WM_RBUTTONDOWN, or WM_MBUTTONDOWN is issued (and more recently WM_XBUTTONDOWN
544
+ for five-button mice), we set up a timer with a period of SP->mouse_wait
545
+ milliseconds. There are then two possibilities. The user will release the
546
+ button quickly (so it's a "click") or they won't (and it's a "press/release").
547
+
548
+ In the first case, we'll get the WM_xBUTTONUP message before the
549
+ WM_TIMER one. We'll kill the timer and set up the BUTTON_CLICKED state. (*)
550
+
551
+ In the second case, we'll get the WM_TIMER message first, so we'll
552
+ set the BUTTON_PRESSED state and kill the timer. Eventually, the user
553
+ will get around to letting go of the mouse button, and we'll get that
554
+ WM_xBUTTONUP message. At that time, we'll set the BUTTON_RELEASED state
555
+ and add the second KEY_MOUSE to the key queue.
556
+
557
+ Also, note that if there is already a KEY_MOUSE to the queue, there's
558
+ no point in adding another one. At least at present, the actual mouse
559
+ events aren't queued anyway. So if there was, say, a click and then a
560
+ release without getch( ) being called in between, you'd then have two
561
+ KEY_MOUSEs on the queue, but would have lost all information about what
562
+ the first one actually was. Hence the code near the end of this function
563
+ to ensure there isn't already a KEY_MOUSE in the queue.
564
+
565
+ Also, a note about wheel handling. Pre-Vista, you could just say
566
+ "the wheel went up" or "the wheel went down". Vista introduced the possibility
567
+ that the mouse motion could be a smoothly varying quantity. So on each
568
+ mouse move, we add in the amount moved, then check to see if that's
569
+ enough to trigger a wheel up/down event (or possibly several). The idea
570
+ is that whereas before, each movement would be 120 units (the default),
571
+ you might now get a series of 40-unit moves and should emit a wheel up/down
572
+ event on every third move.
573
+
574
+ (*) Things are actually slightly more complicated than this. In general,
575
+ it'll just be a plain old BUTTON_CLICKED state. But if there was another
576
+ BUTTON_CLICKED within the last 2 * SP->mouse_wait milliseconds, then this
577
+ must be a _double_ click, so we set the BUTTON_DOUBLE_CLICKED state. And
578
+ if, within that time frame, there was a double or triple click, then we
579
+ set the BUTTON_TRIPLE_CLICKED state. There isn't a "quad" or higher state,
580
+ so if you quadruple-click the mouse, with each click separated by less
581
+ than 2 * SP->mouse_wait milliseconds, then the messages sent will be
582
+ BUTTON_CLICKED, BUTTON_DOUBLE_CLICKED, BUTTON_TRIPLE_CLICKED, and
583
+ then another BUTTON_TRIPLE_CLICKED. */
584
+
585
+ static int set_mouse( const int button_index, const int button_state,
586
+ const LPARAM lParam)
587
+ {
588
+ int i, n_key_mouse_to_add = 1;
589
+ POINT pt;
590
+
591
+ pt.x = LOWORD( lParam);
592
+ pt.y = HIWORD( lParam);
593
+ if( button_index == -1) /* mouse moved, no button */
594
+ n_key_mouse_to_add = 1;
595
+ else
596
+ {
597
+ memset(&pdc_mouse_status, 0, sizeof(MOUSE_STATUS));
598
+ if( button_index < PDC_MAX_MOUSE_BUTTONS)
599
+ {
600
+ if( button_index < 3)
601
+ {
602
+ pdc_mouse_status.button[button_index] = (short)button_state;
603
+ pdc_mouse_status.changes = (1 << button_index);
604
+ }
605
+ else
606
+ {
607
+ pdc_mouse_status.xbutton[button_index - 3] = (short)button_state;
608
+ pdc_mouse_status.changes = (0x40 << button_index);
609
+ }
610
+ }
611
+ else /* actually a wheel mouse movement */
612
+ { /* button_state = number of units moved */
613
+ static int mouse_wheel_vertical_loc = 0;
614
+ static int mouse_wheel_horizontal_loc = 0;
615
+ const int mouse_wheel_sensitivity = 120;
616
+
617
+ n_key_mouse_to_add = 0;
618
+ if( button_index == VERTICAL_WHEEL_EVENT)
619
+ {
620
+ mouse_wheel_vertical_loc += button_state;
621
+ while( mouse_wheel_vertical_loc > mouse_wheel_sensitivity / 2)
622
+ {
623
+ n_key_mouse_to_add++;
624
+ mouse_wheel_vertical_loc -= mouse_wheel_sensitivity;
625
+ pdc_mouse_status.changes |= PDC_MOUSE_WHEEL_UP;
626
+ }
627
+ while( mouse_wheel_vertical_loc < -mouse_wheel_sensitivity / 2)
628
+ {
629
+ n_key_mouse_to_add++;
630
+ mouse_wheel_vertical_loc += mouse_wheel_sensitivity;
631
+ pdc_mouse_status.changes |= PDC_MOUSE_WHEEL_DOWN;
632
+ }
633
+ }
634
+ else /* must be a horizontal event: */
635
+ {
636
+ mouse_wheel_horizontal_loc += button_state;
637
+ while( mouse_wheel_horizontal_loc > mouse_wheel_sensitivity / 2)
638
+ {
639
+ n_key_mouse_to_add++;
640
+ mouse_wheel_horizontal_loc -= mouse_wheel_sensitivity;
641
+ pdc_mouse_status.changes |= PDC_MOUSE_WHEEL_RIGHT;
642
+ }
643
+ while( mouse_wheel_horizontal_loc < -mouse_wheel_sensitivity / 2)
644
+ {
645
+ n_key_mouse_to_add++;
646
+ mouse_wheel_horizontal_loc += mouse_wheel_sensitivity;
647
+ pdc_mouse_status.changes |= PDC_MOUSE_WHEEL_LEFT;
648
+ }
649
+ }
650
+ /* I think it may be that for wheel events, we */
651
+ /* return x = y = -1, rather than getting the */
652
+ /* actual mouse position. I don't like this, but */
653
+ /* I like messing up existing apps even less. */
654
+ pt.x = -PDC_cxChar;
655
+ pt.y = -PDC_cyChar;
656
+ /* ScreenToClient( PDC_hWnd, &pt); Wheel posns are in screen, */
657
+ } /* not client, coords; gotta xform them */
658
+ }
659
+ pdc_mouse_status.x = pt.x / PDC_cxChar;
660
+ pdc_mouse_status.y = pt.y / PDC_cyChar;
661
+ /* if( SP->save_key_modifiers) */
662
+ {
663
+ int i, button_flags = 0;
664
+
665
+ if( GetKeyState( VK_MENU) & 0x8000)
666
+ button_flags |= PDC_BUTTON_ALT;
667
+
668
+ if( GetKeyState( VK_SHIFT) & 0x8000)
669
+ button_flags |= PDC_BUTTON_SHIFT;
670
+
671
+ if( GetKeyState( VK_CONTROL) & 0x8000)
672
+ button_flags |= PDC_BUTTON_CONTROL;
673
+
674
+ for (i = 0; i < 3; i++)
675
+ pdc_mouse_status.button[i] |= button_flags;
676
+ for (i = 0; i < PDC_N_EXTENDED_MOUSE_BUTTONS; i++)
677
+ pdc_mouse_status.xbutton[i] |= button_flags;
678
+ }
679
+ /* If there is already a KEY_MOUSE in the queue, we */
680
+ /* don't really want to add another one. See above. */
681
+ i = PDC_key_queue_low;
682
+ while( i != PDC_key_queue_high)
683
+ {
684
+ if( PDC_key_queue[i] == KEY_MOUSE)
685
+ {
686
+ debug_printf( "Mouse key already in queue\n");
687
+ return( 0);
688
+ }
689
+ i = (i + 1) % KEY_QUEUE_SIZE;
690
+ }
691
+ /* If the window is maximized, the click may occur just */
692
+ /* outside the "real" screen area. If so, we again */
693
+ /* don't want to add a key to the queue: */
694
+ if( pdc_mouse_status.x >= PDC_n_cols || pdc_mouse_status.y >= PDC_n_rows)
695
+ n_key_mouse_to_add = 0;
696
+ /* OK, there isn't a KEY_MOUSE already in the queue. */
697
+ /* So we'll add one (or zero or more, for wheel mice): */
698
+ while( n_key_mouse_to_add--)
699
+ add_key_to_queue( KEY_MOUSE);
700
+ return( 0);
701
+ }
702
+
703
+ /* The following should be #defined in 'winuser.h', but such is */
704
+ /* not always the case. The following fixes the exceptions: */
705
+ #ifndef WM_MOUSEWHEEL
706
+ #define WM_MOUSEWHEEL 0x020A
707
+ #endif
708
+ #ifndef WM_MOUSEHWHEEL
709
+ #define WM_MOUSEHWHEEL 0x020E
710
+ #endif
711
+ #ifndef WM_XBUTTONDOWN
712
+ #define WM_XBUTTONDOWN 0x020B
713
+ #define WM_XBUTTONUP 0x020C
714
+ #endif
715
+ #ifndef MK_XBUTTON1
716
+ #define MK_XBUTTON1 0x0020
717
+ #define MK_XBUTTON2 0x0040
718
+ #endif
719
+
720
+ #ifdef USE_FALLBACK_FONT
721
+ extern GLYPHSET *PDC_unicode_range_data;
722
+ #endif /* #ifdef USE_FALLBACK_FONT */
723
+
724
+ int PDC_blink_state = 0;
725
+ #define TIMER_ID_FOR_BLINKING 0x2000
726
+
727
+ /* When first loading a font, we use 'get_character_sizes' to briefly
728
+ load the (non-bold, non-italic flavor of the) font, get its height and
729
+ width, and call GetFontUnicodeRanges to determine which characters are
730
+ actually available from that font. That set of ranges is used so that,
731
+ when we come across characters not in the font, we can switch to a
732
+ "fallback" font (Unifont, most likely). */
733
+
734
+ static void get_character_sizes( const HWND hwnd,
735
+ int *xchar_size, int *ychar_size)
736
+ {
737
+ HFONT hFont = PDC_get_font_handle( 0);
738
+ HFONT prev_font;
739
+ HDC hdc = GetDC (hwnd) ;
740
+ TEXTMETRIC tm ;
741
+ #ifdef USE_FALLBACK_FONT
742
+ DWORD size;
743
+ #endif
744
+
745
+ prev_font = SelectObject (hdc, hFont);
746
+ GetTextMetrics (hdc, &tm) ;
747
+ #ifdef USE_FALLBACK_FONT
748
+ assert( !PDC_unicode_range_data);
749
+ size = GetFontUnicodeRanges( hdc, NULL);
750
+ PDC_unicode_range_data = (GLYPHSET *)calloc( 1, size);
751
+ PDC_unicode_range_data->cbThis = size;
752
+ size = GetFontUnicodeRanges( hdc, PDC_unicode_range_data);
753
+ #endif /* #ifdef USE_FALLBACK_FONT */
754
+ SelectObject( hdc, prev_font);
755
+ ReleaseDC (hwnd, hdc) ;
756
+ DeleteObject( hFont);
757
+ *xchar_size = tm.tmAveCharWidth ;
758
+ *ychar_size = tm.tmHeight;
759
+ }
760
+
761
+ INLINE void sort_out_rect( RECT *rect)
762
+ {
763
+ int temp;
764
+
765
+ if( rect->left > rect->right)
766
+ {
767
+ temp = rect->right;
768
+ rect->right = rect->left;
769
+ rect->left = temp;
770
+ }
771
+ if( rect->top > rect->bottom)
772
+ {
773
+ temp = rect->bottom;
774
+ rect->bottom = rect->top;
775
+ rect->top = temp;
776
+ }
777
+ }
778
+
779
+ static int rectangle_from_chars_to_pixels( RECT *rect)
780
+ {
781
+ int rval = 1;
782
+
783
+ if( rect->right == rect->left && rect->top == rect->bottom)
784
+ rval = 0;
785
+ sort_out_rect( rect);
786
+ if( rect->top < 0)
787
+ rval = 0;
788
+ rect->right++;
789
+ rect->bottom++;
790
+ rect->left *= PDC_cxChar;
791
+ rect->right *= PDC_cxChar;
792
+ rect->top *= PDC_cyChar;
793
+ rect->bottom *= PDC_cyChar;
794
+ return( rval);
795
+ }
796
+
797
+ /* When updating the mouse rectangle, you _could_ just remove the old one
798
+ and draw the new one. But that sometimes caused flickering if the mouse
799
+ area was large. In such cases, it's better to determine what areas
800
+ actually changed, and invert just those. So the following checks to
801
+ see if two overlapping rectangles are being drawn (this is the norm)
802
+ and figures out the area that actually needs to be flipped. It does
803
+ seem to decrease flickering to near-zero. */
804
+
805
+ static int PDC_selecting_rectangle = 1;
806
+
807
+ int PDC_find_ends_of_selected_text( const int line,
808
+ const RECT *rect, int *x)
809
+ {
810
+ int rval = 0, i;
811
+
812
+ if( (rect->top - line) * (rect->bottom - line) <= 0
813
+ && (rect->top != rect->bottom || rect->left != rect->right))
814
+ {
815
+ if( PDC_selecting_rectangle || rect->top == rect->bottom)
816
+ {
817
+ x[0] = min( rect->right, rect->left);
818
+ x[1] = max( rect->right, rect->left);
819
+ rval = 1;
820
+ }
821
+ else if( rect->top <= line && line <= rect->bottom)
822
+ {
823
+ x[0] = (line == rect->top ? rect->left : 0);
824
+ x[1] = (line == rect->bottom ? rect->right : SP->cols - 1);
825
+ rval = 1;
826
+ }
827
+ else if( rect->top >= line && line >= rect->bottom)
828
+ {
829
+ x[0] = (line == rect->bottom ? rect->right : 0);
830
+ x[1] = (line == rect->top ? rect->left : SP->cols - 1);
831
+ rval = 1;
832
+ }
833
+ }
834
+ if( rval)
835
+ for( i = 0; i < 2; i++)
836
+ if( x[i] > SP->cols - 1)
837
+ x[i] = SP->cols - 1;
838
+ return( rval);
839
+ }
840
+
841
+ /* Called in only one place, so let's inline it */
842
+
843
+ INLINE void show_mouse_rect( const HWND hwnd, RECT before, RECT after)
844
+ {
845
+ if( before.top > -1 || after.top > -1)
846
+ if( memcmp( &after, &before, sizeof( RECT)))
847
+ {
848
+ const HDC hdc = GetDC( hwnd) ;
849
+
850
+ if( PDC_selecting_rectangle)
851
+ {
852
+ const int show_before = rectangle_from_chars_to_pixels( &before);
853
+ const int show_after = rectangle_from_chars_to_pixels( &after);
854
+
855
+ if( show_before && show_after)
856
+ {
857
+ RECT temp;
858
+
859
+ if( before.top < after.top)
860
+ {
861
+ temp = before; before = after; after = temp;
862
+ }
863
+ if( before.top < after.bottom && after.right > before.left
864
+ && before.right > after.left)
865
+ {
866
+ const int tval = min( after.bottom, before.bottom);
867
+
868
+ temp = after;
869
+ temp.bottom = before.top;
870
+ InvertRect( hdc, &temp);
871
+
872
+ temp.top = temp.bottom;
873
+ temp.bottom = tval;
874
+ temp.right = max( after.right, before.right);
875
+ temp.left = min( after.right, before.right);
876
+ InvertRect( hdc, &temp);
877
+
878
+ temp.right = max( after.left, before.left);
879
+ temp.left = min( after.left, before.left);
880
+ InvertRect( hdc, &temp);
881
+
882
+ temp = (after.bottom > before.bottom ? after : before);
883
+ temp.top = tval;
884
+ InvertRect( hdc, &temp);
885
+ }
886
+ }
887
+ else if( show_before)
888
+ InvertRect( hdc, &before);
889
+ else if( show_after)
890
+ InvertRect( hdc, &after);
891
+ }
892
+ else /* _not_ selecting rectangle; selecting lines */
893
+ {
894
+ int line;
895
+
896
+ for( line = 0; line < SP->lines; line++)
897
+ {
898
+ int x[4], n_rects = 0, i;
899
+
900
+ n_rects = PDC_find_ends_of_selected_text( line, &before, x);
901
+ n_rects += PDC_find_ends_of_selected_text( line, &after, x + n_rects * 2);
902
+ if( n_rects == 2)
903
+ if( x[0] == x[2] && x[1] == x[3])
904
+ n_rects = 0; /* Rects are same & will cancel */
905
+ for( i = 0; i < n_rects; i++)
906
+ {
907
+ RECT trect;
908
+
909
+ trect.left = x[i + i];
910
+ trect.right = x[i + i + 1];
911
+ trect.top = line;
912
+ trect.bottom = line;
913
+ rectangle_from_chars_to_pixels( &trect);
914
+ InvertRect( hdc, &trect);
915
+ }
916
+ }
917
+ }
918
+ ReleaseDC( hwnd, hdc) ;
919
+ }
920
+ }
921
+
922
+ /* Cygwin lacks _splitpath, _wsplitpath. THE FOLLOWING ARE NOT FULLY
923
+ TESTED IMPLEMENTATIONS OF THOSE TWO FUNCTIONS, because the only use we
924
+ make of them is to get fname. (Though I did write a little test program,
925
+ and they seem to work.) */
926
+
927
+ #ifdef __CYGWIN__
928
+ #ifdef PDC_WIDE
929
+ static void my_wsplitpath( const wchar_t *path, wchar_t *drive,
930
+ wchar_t *dir, wchar_t *fname, wchar_t *ext)
931
+ {
932
+ size_t i, loc = 0;
933
+
934
+ assert( path);
935
+ assert( fname);
936
+ if( path[0] && path[1] == ':')
937
+ {
938
+ if( drive)
939
+ {
940
+ drive[0] = path[0];
941
+ drive[1] = ':';
942
+ drive[2] = '\0';
943
+ }
944
+ path += 2;
945
+ }
946
+ else if( drive)
947
+ *drive = '\0';
948
+ for( i = 0; path[i]; i++)
949
+ if( path[i] == '/' || path[i] == '\\')
950
+ loc = i + 1;
951
+ if( dir)
952
+ {
953
+ memcpy( dir, path, loc * sizeof( wchar_t));
954
+ dir[loc] = '\0';
955
+ }
956
+ if( loc)
957
+ path += loc;
958
+ loc = 0;
959
+ while( path[loc] && path[loc] != '.')
960
+ loc++;
961
+ if( fname)
962
+ {
963
+ memcpy( fname, path, loc * sizeof( wchar_t));
964
+ fname[loc] = '\0';
965
+ }
966
+ if( ext)
967
+ wcscpy( ext, path + loc);
968
+ }
969
+ #endif /* #ifdef PDC_WIDE */
970
+
971
+ static void my_splitpath( const char *path, char *drive,
972
+ char *dir, char *fname, char *ext)
973
+ {
974
+ size_t i, loc = 0;
975
+
976
+ assert( path);
977
+ assert( fname);
978
+ if( path[0] && path[1] == ':')
979
+ {
980
+ if( drive)
981
+ {
982
+ drive[0] = path[0];
983
+ drive[1] = ':';
984
+ drive[2] = '\0';
985
+ }
986
+ path += 2;
987
+ }
988
+ else if( drive)
989
+ *drive = '\0';
990
+ for( i = 0; path[i]; i++)
991
+ if( path[i] == '/' || path[i] == '\\')
992
+ loc = i + 1;
993
+ if( dir)
994
+ {
995
+ memcpy( dir, path, loc * sizeof( char));
996
+ dir[loc] = '\0';
997
+ }
998
+ if( loc)
999
+ path += loc;
1000
+ loc = 0;
1001
+ while( path[loc] && path[loc] != '.')
1002
+ loc++;
1003
+ if( fname)
1004
+ {
1005
+ memcpy( fname, path, loc * sizeof( char));
1006
+ fname[loc] = '\0';
1007
+ }
1008
+ if( ext)
1009
+ strcpy( ext, path + loc);
1010
+ }
1011
+ #else /* non-Cygwin case : */
1012
+ #define my_splitpath _splitpath
1013
+ #define my_wsplitpath _wsplitpath
1014
+ #define GOT_ARGV_ARGC
1015
+ #endif /* #ifdef __CYGWIN__ */
1016
+
1017
+ /* This function looks at the full command line, which includes a fully
1018
+ specified path to the executable and arguments; and strips out just the
1019
+ name of the app, with the arguments optionally appended. Hence,
1020
+
1021
+ C:\PDCURSES\WINGUI\TESTCURS.EXE arg1 arg2
1022
+
1023
+ would be reduced to 'Testcurs' (if include_args == 0) or
1024
+ 'Testcurs arg1 arg2' (if include_args == 1). The former case is used to
1025
+ create a (hopefully unique) registry key for the app, so that the app's
1026
+ specific settings (screen and font size) will be stored for the next run.
1027
+ The latter case is used to generate a default window title.
1028
+
1029
+ Unfortunately, this code has to do some pretty strange things. In the
1030
+ Unicode (PDC_WIDE) case, we really should use __wargv; but that pointer
1031
+ may or may not be NULL. If it's NULL, we fall back on __argv. In at
1032
+ least one case, where this code is compiled into a DLL using MinGW and
1033
+ then used in an app compiled with MS Visual C, __argv isn't set either,
1034
+ and we drop back to looking at GetCommandLine( ). Which leads to a real
1035
+ oddity: GetCommandLine( ) may return something such as, say,
1036
+
1037
+ "C:\PDCurses\WinGUI\testcurs.exe" -lRussian
1038
+
1039
+ ...which, after being run through _splitpath or _wsplitpath, becomes
1040
+
1041
+ testcurs.exe" -lRussian
1042
+
1043
+ The .exe" is removed, and the command-line arguments shifted or removed,
1044
+ depending on the value of include_args. Pretty strange stuff.
1045
+
1046
+ However, if one calls Xinitscr( ) and passed command-line arguments when
1047
+ starting this library, those arguments will be stored in PDC_argc and
1048
+ PDC_argv, and will be used instead of GetCommandLine.
1049
+ */
1050
+
1051
+ #ifdef UNICODE
1052
+ #define my_stprintf wsprintf
1053
+ #define my_tcslen wcslen
1054
+ #ifdef __CYGWIN__
1055
+ /* Can't lowercase Unicode text in Cygwin */
1056
+ #define my_tcslwr
1057
+ #elif defined _MSC_VER
1058
+ #define my_tcslwr _wcslwr
1059
+ #else
1060
+ #define my_tcslwr wcslwr
1061
+ #endif /* __CYGWIN__ */
1062
+ #define my_tcscat wcscat
1063
+ #define my_tcscpy wcscpy
1064
+ #define my_stscanf swscanf
1065
+
1066
+ #else /* UNICODE */
1067
+
1068
+ #define my_stprintf sprintf
1069
+ #define my_tcslen strlen
1070
+ #define my_tcslwr strlwr
1071
+ #ifdef _MSC_VER
1072
+ #define strlwr _strlwr
1073
+ #endif
1074
+ #define my_tcscat strcat
1075
+ #define my_tcscpy strcpy
1076
+ #define my_stscanf sscanf
1077
+ #endif /* UNICODE */
1078
+
1079
+
1080
+ static void get_app_name( TCHAR *buff, const size_t buff_size, const bool include_args)
1081
+ {
1082
+ int i;
1083
+ size_t buff_space;
1084
+ #ifdef GOT_ARGV_ARGC
1085
+ int argc = (PDC_argc ? PDC_argc : __argc);
1086
+ char **argv = (PDC_argc ? PDC_argv : __argv);
1087
+ #else
1088
+ int argc = PDC_argc;
1089
+ char **argv = PDC_argv;
1090
+ #endif
1091
+
1092
+ #ifdef PDC_WIDE
1093
+ wchar_t **wargv = __wargv;
1094
+ #ifdef GOT_ARGV_ARGC
1095
+ /* in case we can not access the array directly try to get it otherwise */
1096
+ if( !wargv) {
1097
+ wchar_t *cmd_linew = GetCommandLine( );
1098
+ if (cmd_linew) {
1099
+ wargv = CommandLineToArgvW (cmd_linew, &argc);
1100
+ }
1101
+ }
1102
+ if( wargv)
1103
+ {
1104
+ my_wsplitpath( wargv[0], NULL, NULL, buff, NULL);
1105
+ if ( include_args)
1106
+ {
1107
+ buff_space = buff_size - my_tcslen( buff) - 1;
1108
+ for ( i = 1; i < argc; i++)
1109
+ {
1110
+ size_t arg_len = my_tcslen( wargv[i]) + 1;
1111
+ if ( buff_space < arg_len) {
1112
+ break;
1113
+ }
1114
+ buff_space -= arg_len;
1115
+ wcscat( buff, L" ");
1116
+ wcscat( buff, wargv[i]);
1117
+ }
1118
+ }
1119
+ }
1120
+ else
1121
+ #endif /* #ifdef GOT_ARGV_ARGC */
1122
+ if( argv)
1123
+ {
1124
+ char tbuff[MAX_PATH];
1125
+ my_splitpath( argv[0], NULL, NULL, tbuff, NULL);
1126
+ if ( include_args)
1127
+ {
1128
+ buff_space = buff_size - strlen( tbuff) - 1;
1129
+ for ( i = 1; i < argc; i++)
1130
+ {
1131
+ size_t arg_len = strlen( argv[i]) + 1;
1132
+ if ( buff_space < arg_len) {
1133
+ break;
1134
+ }
1135
+ buff_space -= arg_len;
1136
+ strcat( tbuff, " ");
1137
+ strcat( tbuff, argv[i]);
1138
+ }
1139
+ }
1140
+ mbstowcs( buff, tbuff, strlen( tbuff) + 1);
1141
+ }
1142
+ else /* no __argv or PDC_argv pointer available */
1143
+ {
1144
+ wchar_t *tptr;
1145
+
1146
+ my_wsplitpath( GetCommandLine( ), NULL, NULL, buff, NULL);
1147
+ my_tcslwr( buff + 1);
1148
+ tptr = wcsstr( buff, L".exe\"");
1149
+ if( tptr)
1150
+ {
1151
+ if( include_args)
1152
+ memmove( tptr, tptr + 5, wcslen( tptr + 4) * sizeof( wchar_t));
1153
+ else
1154
+ *tptr = '\0';
1155
+ }
1156
+ }
1157
+ #else /* non-Unicode case */
1158
+ if( argv)
1159
+ {
1160
+ my_splitpath( argv[0], NULL, NULL, buff, NULL);
1161
+ debug_printf( "Path: %s; exe: %s\n", argv[0], buff);
1162
+ if ( include_args)
1163
+ {
1164
+ buff_space = buff_size - my_tcslen( buff) - 1;
1165
+ for ( i = 1; i < argc; i++)
1166
+ {
1167
+ size_t arg_len = my_tcslen( argv[i]) + 1;
1168
+ if ( buff_space < arg_len) {
1169
+ break;
1170
+ }
1171
+ buff_space -= arg_len;
1172
+ strcat( buff, " ");
1173
+ strcat( buff, argv[i]);
1174
+ }
1175
+ }
1176
+ }
1177
+ else /* no __argv pointer available */
1178
+ {
1179
+ char *tptr;
1180
+
1181
+ my_splitpath( GetCommandLine( ), NULL, NULL, buff, NULL);
1182
+ strlwr( buff + 1);
1183
+ tptr = strstr( buff, ".exe\"");
1184
+ if( tptr)
1185
+ {
1186
+ if( include_args)
1187
+ memmove( tptr, tptr + 5, strlen( tptr + 4));
1188
+ else
1189
+ *tptr = '\0';
1190
+ }
1191
+ }
1192
+ #endif
1193
+ my_tcslwr( buff + 1);
1194
+ }
1195
+
1196
+ /* This function extracts the first icon from the executable that is
1197
+ executing this DLL */
1198
+
1199
+ INLINE HICON get_app_icon( )
1200
+ {
1201
+ #ifdef PDC_WIDE
1202
+ wchar_t filename[MAX_PATH];
1203
+ #else
1204
+ char filename[MAX_PATH];
1205
+ #endif
1206
+
1207
+ HICON icon = NULL;
1208
+ if ( GetModuleFileName( NULL, filename, sizeof(filename) ) != 0 )
1209
+ icon = ExtractIcon( 0, filename, 0 );
1210
+ return icon;
1211
+ }
1212
+
1213
+ extern TCHAR PDC_font_name[];
1214
+
1215
+ /* This flavor of Curses tries to store the window and font sizes on
1216
+ an app-by-app basis. To do this, it uses the above get_app_name( )
1217
+ function, then sets or gets a corresponding value from the Windoze
1218
+ registry. The benefit should be that one can have one screen size/font
1219
+ for, say, Testcurs, while having different settings for, say, Firework
1220
+ or Rain or one's own programs. */
1221
+
1222
+ INLINE int set_default_sizes_from_registry( const int n_cols, const int n_rows,
1223
+ const int xloc, const int yloc, const int menu_shown)
1224
+ {
1225
+ DWORD is_new_key;
1226
+ HKEY hNewKey;
1227
+ long rval = RegCreateKeyEx( HKEY_CURRENT_USER, _T( "SOFTWARE\\PDCurses"),
1228
+ 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
1229
+ 0, &hNewKey, &is_new_key);
1230
+
1231
+ if( rval == ERROR_SUCCESS)
1232
+ {
1233
+ TCHAR buff[180];
1234
+ TCHAR key_name[MAX_PATH];
1235
+ extern int PDC_font_size;
1236
+
1237
+ if( IsZoomed( PDC_hWnd)) /* -1x-1 indicates a maximized window */
1238
+ my_stprintf( buff,
1239
+ _T( "-1x-1,%d,0,0,%d"), PDC_font_size, menu_shown);
1240
+ else
1241
+ my_stprintf( buff,
1242
+ _T( "%dx%d,%d,%d,%d,%d"), n_cols, n_rows, PDC_font_size,
1243
+ xloc, yloc, menu_shown);
1244
+ my_stprintf( buff + my_tcslen( buff),
1245
+ _T(";%d,%d,%d,%d:"),
1246
+ min_lines, max_lines,
1247
+ min_cols, max_cols);
1248
+ my_tcscat( buff, PDC_font_name);
1249
+
1250
+ get_app_name( key_name, MAX_PATH, FALSE);
1251
+ rval = RegSetValueEx( hNewKey, key_name, 0, REG_SZ,
1252
+ (BYTE *)buff, (DWORD)( my_tcslen( buff) * sizeof( TCHAR)));
1253
+ RegCloseKey( hNewKey);
1254
+ }
1255
+ debug_printf( "Size: %d %d; %d\n", n_cols, n_rows, rval);
1256
+ return( rval != ERROR_SUCCESS);
1257
+ }
1258
+
1259
+ /* If the window is maximized, there will usually be a fractional
1260
+ character width at the right and bottom edges. The following code fills
1261
+ that in with a black brush. It takes the "paint rectangle", the area
1262
+ passed with a WM_PAINT message that specifies what chunk of the client
1263
+ area needs to be redrawn.
1264
+
1265
+ If the window is _not_ maximized, this shouldn't happen; the window
1266
+ width/height should always be an integral multiple of the character
1267
+ width/height, with no slivers at the right and bottom edges. */
1268
+
1269
+ static void fix_up_edges( const HDC hdc, const RECT *rect)
1270
+ {
1271
+ const int x = PDC_n_cols * PDC_cxChar;
1272
+ const int y = PDC_n_rows * PDC_cyChar;
1273
+
1274
+ if( rect->right >= x || rect->bottom >= y)
1275
+ {
1276
+ const HBRUSH hOldBrush =
1277
+ SelectObject( hdc, GetStockObject( BLACK_BRUSH));
1278
+
1279
+ SelectObject( hdc, GetStockObject( NULL_PEN));
1280
+ if( rect->right >= x)
1281
+ Rectangle( hdc, x, rect->top, rect->right + 1, rect->bottom + 1);
1282
+ if( rect->bottom >= y)
1283
+ Rectangle( hdc, rect->left, y, rect->right + 1, rect->bottom + 1);
1284
+ SelectObject( hdc, hOldBrush);
1285
+ }
1286
+ }
1287
+
1288
+ static void adjust_font_size( const int font_size_change)
1289
+ {
1290
+ extern int PDC_font_size;
1291
+
1292
+ PDC_font_size += font_size_change;
1293
+ if( PDC_font_size < 2)
1294
+ PDC_font_size = 2;
1295
+ PDC_transform_line( 0, 0, 0, NULL); /* free any fonts */
1296
+ get_character_sizes( PDC_hWnd, &PDC_cxChar, &PDC_cyChar);
1297
+ /* When the font size changes, do we want to keep */
1298
+ /* the window the same size (except to remove any */
1299
+ /* fractional character)? Or do we keep the number */
1300
+ /* of rows/columns the same? For the nonce, I'm */
1301
+ /* keeping the window size fixed if the window is */
1302
+ /* maximized, but keeping the number of rows/lines */
1303
+ /* fixed if it's windowed. That's my opinion. If */
1304
+ /* you disagree, I have others. */
1305
+ if( IsZoomed( PDC_hWnd))
1306
+ {
1307
+ RECT client_rect;
1308
+ HDC hdc;
1309
+
1310
+ GetClientRect( PDC_hWnd, &client_rect);
1311
+ PDC_n_rows = client_rect.bottom / PDC_cyChar;
1312
+ PDC_n_cols = client_rect.right / PDC_cxChar;
1313
+ keep_size_within_bounds( &PDC_n_rows, &PDC_n_cols);
1314
+ PDC_resize_screen( PDC_n_rows, PDC_n_cols);
1315
+ add_key_to_queue( KEY_RESIZE);
1316
+ SP->resized = TRUE;
1317
+ hdc = GetDC (PDC_hWnd) ;
1318
+ GetClientRect( PDC_hWnd, &client_rect);
1319
+ fix_up_edges( hdc, &client_rect);
1320
+ ReleaseDC( PDC_hWnd, hdc) ;
1321
+ }
1322
+ else
1323
+ {
1324
+ PDC_resize_screen( PDC_n_rows, PDC_n_cols);
1325
+ InvalidateRect( PDC_hWnd, NULL, FALSE);
1326
+ }
1327
+ }
1328
+
1329
+ /* PDC_mouse_rect is the area currently highlit by dragging the */
1330
+ /* mouse. It's global, sadly, because we need to ensure that */
1331
+ /* the highlighting is respected when the text within that */
1332
+ /* rectangle is redrawn by PDC_transform_line(). */
1333
+ RECT PDC_mouse_rect = { -1, -1, -1, -1 };
1334
+
1335
+ int PDC_setclipboard_raw( const char *contents, long length,
1336
+ const bool translate_multibyte_to_wide_char);
1337
+
1338
+ /* Called in only one place (when the left mouse button goes up), */
1339
+ /* so we should inline it : */
1340
+
1341
+ INLINE void HandleBlockCopy( void)
1342
+ {
1343
+ int i, j, len, x[2];
1344
+ TCHAR *buff, *tptr;
1345
+
1346
+ /* Make a first pass to determine how much text is blocked: */
1347
+ for( i = len = 0; i < SP->lines; i++)
1348
+ if( PDC_find_ends_of_selected_text( i, &PDC_mouse_rect, x))
1349
+ len += x[1] - x[0] + 3;
1350
+ buff = tptr = (TCHAR *)malloc( (len + 1) * sizeof( TCHAR));
1351
+ /* Make second pass to copy that text to a buffer: */
1352
+ for( i = len = 0; i < SP->lines; i++)
1353
+ if( PDC_find_ends_of_selected_text( i, &PDC_mouse_rect, x))
1354
+ {
1355
+ const chtype *cptr = curscr->_y[i];
1356
+
1357
+ for( j = 0; j < x[1] - x[0] + 1; j++)
1358
+ tptr[j] = (TCHAR)cptr[j + x[0]];
1359
+ while( j > 0 && tptr[j - 1] == ' ')
1360
+ j--; /* remove trailing spaces */
1361
+ tptr += j;
1362
+ *tptr++ = (TCHAR)13;
1363
+ *tptr++ = (TCHAR)10;
1364
+ }
1365
+ if( tptr != buff) /* at least one line read in */
1366
+ {
1367
+ tptr[-2] = '\0'; /* cut off the last CR/LF */
1368
+ PDC_setclipboard_raw( (char *)buff, (long)( tptr - buff), FALSE);
1369
+ }
1370
+ free( buff);
1371
+ }
1372
+
1373
+ #define WM_ENLARGE_FONT (WM_USER + 1)
1374
+ #define WM_SHRINK_FONT (WM_USER + 2)
1375
+ #define WM_MARK_AND_COPY (WM_USER + 3)
1376
+ #define WM_TOGGLE_MENU (WM_USER + 4)
1377
+ #define WM_EXIT_GRACELESSLY (WM_USER + 5)
1378
+ #define WM_CHOOSE_FONT (WM_USER + 6)
1379
+
1380
+ static int add_resize_key = 1;
1381
+
1382
+ /*man-start**************************************************************
1383
+
1384
+ Resize limits
1385
+ -------------
1386
+
1387
+ ### Synopsis
1388
+
1389
+ void PDC_set_resize_limits( const int new_min_lines,
1390
+ const int new_max_lines,
1391
+ const int new_min_cols,
1392
+ const int new_max_cols);
1393
+
1394
+ ### Description
1395
+
1396
+ For platforms supporting resizable windows (SDLx, WinGUI, X11). Some
1397
+ programs may be unprepared for a resize event; for these, calling
1398
+ this function with the max and min limits equal ensures that no
1399
+ user resizing can be done. Other programs may require at least a
1400
+ certain number, and/or no more than a certain number, of columns
1401
+ and/or lines.
1402
+
1403
+ ### Portability
1404
+
1405
+ PDCurses-only function.
1406
+
1407
+ **man-end****************************************************************/
1408
+
1409
+ void PDC_set_resize_limits( const int new_min_lines, const int new_max_lines,
1410
+ const int new_min_cols, const int new_max_cols)
1411
+ {
1412
+ min_lines = max( new_min_lines, 2);
1413
+ max_lines = max( new_max_lines, min_lines);
1414
+ min_cols = max( new_min_cols, 2);
1415
+ max_cols = max( new_max_cols, min_cols);
1416
+ }
1417
+
1418
+ /* The screen should hold the characters (PDC_cxChar * n_default_columns */
1419
+ /* pixels wide, similarly high). In width, we need two frame widths, */
1420
+ /* one on each side. Vertically, we need two frame heights, plus room */
1421
+ /* for the application title and the menu. */
1422
+
1423
+ static void adjust_window_size( int *xpixels, int *ypixels, int window_style,
1424
+ const int menu_shown)
1425
+ {
1426
+ RECT rect;
1427
+
1428
+ rect.left = rect.top = 0;
1429
+ rect.right = *xpixels;
1430
+ rect.bottom = *ypixels;
1431
+ /* printf( "Adjusting to %d, %d\n", *xpixels, *ypixels); */
1432
+ AdjustWindowRect( &rect, window_style, menu_shown);
1433
+ *xpixels = rect.right - rect.left;
1434
+ *ypixels = rect.bottom - rect.top;
1435
+ }
1436
+
1437
+ static int keep_size_within_bounds( int *lines, int *cols)
1438
+ {
1439
+ int rval = 0;
1440
+
1441
+ if( *lines < min_lines)
1442
+ {
1443
+ *lines = min_lines;
1444
+ rval = 1;
1445
+ }
1446
+ else if( *lines > max_lines)
1447
+ {
1448
+ *lines = max_lines;
1449
+ rval = 2;
1450
+ }
1451
+ if( *cols < min_cols)
1452
+ {
1453
+ *cols = min_cols;
1454
+ rval |= 4;
1455
+ }
1456
+ else if( *cols > max_cols)
1457
+ {
1458
+ *cols = max_cols;
1459
+ rval |= 8;
1460
+ }
1461
+ return( rval);
1462
+ }
1463
+
1464
+ INLINE int get_default_sizes_from_registry( int *n_cols, int *n_rows,
1465
+ int *xloc, int *yloc, int *menu_shown)
1466
+ {
1467
+ TCHAR data[100];
1468
+ DWORD size_out = sizeof( data);
1469
+ HKEY hKey = 0;
1470
+ long rval = RegOpenKeyEx( HKEY_CURRENT_USER, _T( "SOFTWARE\\PDCurses"),
1471
+ 0, KEY_READ, &hKey);
1472
+
1473
+ if( !hKey)
1474
+ return( 1);
1475
+ if( rval == ERROR_SUCCESS)
1476
+ {
1477
+ TCHAR key_name[MAX_PATH];
1478
+
1479
+ get_app_name( key_name, MAX_PATH, FALSE);
1480
+ rval = RegQueryValueEx( hKey, key_name,
1481
+ NULL, NULL, (BYTE *)data, &size_out);
1482
+ if( rval == ERROR_SUCCESS)
1483
+ {
1484
+ extern int PDC_font_size;
1485
+ int x = -1, y = -1, bytes_read = 0;
1486
+
1487
+ my_stscanf( data, _T( "%dx%d,%d,%d,%d,%d;%d,%d,%d,%d:%n"),
1488
+ &x, &y, &PDC_font_size,
1489
+ xloc, yloc, menu_shown,
1490
+ &min_lines, &max_lines,
1491
+ &min_cols, &max_cols,
1492
+ &bytes_read);
1493
+ if( bytes_read > 0 && data[bytes_read - 1] == ':')
1494
+ my_tcscpy( PDC_font_name, data + bytes_read);
1495
+ if( n_cols)
1496
+ *n_cols = x;
1497
+ if( n_rows)
1498
+ *n_rows = y;
1499
+ if( *n_cols > 0 && *n_rows > 0) /* i.e., not maximized */
1500
+ keep_size_within_bounds( n_rows, n_cols);
1501
+ }
1502
+ RegCloseKey( hKey);
1503
+ }
1504
+ if( rval != ERROR_SUCCESS)
1505
+ debug_printf( "get_default_sizes_from_registry error: %d\n", rval);
1506
+ return( rval != ERROR_SUCCESS);
1507
+ }
1508
+
1509
+ /* Ensure that the dragged rectangle */
1510
+ /* is an even multiple of the char size */
1511
+ INLINE void HandleSizing( WPARAM wParam, LPARAM lParam )
1512
+ {
1513
+ RECT *rect = (RECT *)lParam;
1514
+ RECT window_rect, client_rect;
1515
+ int hadd, vadd, width, height;
1516
+ int n_rows, n_cols;
1517
+ int rounded_width, rounded_height;
1518
+
1519
+ GetWindowRect( PDC_hWnd, &window_rect);
1520
+ GetClientRect( PDC_hWnd, &client_rect);
1521
+ hadd = (window_rect.right - window_rect.left) - client_rect.right;
1522
+ vadd = (window_rect.bottom - window_rect.top) - client_rect.bottom;
1523
+ width = rect->right - rect->left - hadd;
1524
+ height = rect->bottom - rect->top - vadd;
1525
+
1526
+ n_cols = (width + PDC_cxChar / 2) / PDC_cxChar;
1527
+ n_rows = (height + PDC_cyChar / 2) / PDC_cyChar;
1528
+ keep_size_within_bounds( &n_rows, &n_cols);
1529
+
1530
+ rounded_width = hadd + n_cols * PDC_cxChar;
1531
+ rounded_height = vadd + n_rows * PDC_cyChar;
1532
+
1533
+ if( wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT
1534
+ || wParam == WMSZ_BOTTOMRIGHT)
1535
+ rect->bottom = rect->top + rounded_height;
1536
+ if( wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT
1537
+ || wParam == WMSZ_TOPRIGHT)
1538
+ rect->top = rect->bottom - rounded_height;
1539
+ if( wParam == WMSZ_RIGHT || wParam == WMSZ_BOTTOMRIGHT
1540
+ || wParam == WMSZ_TOPRIGHT)
1541
+ rect->right = rect->left + rounded_width;
1542
+ if( wParam == WMSZ_LEFT || wParam == WMSZ_BOTTOMLEFT
1543
+ || wParam == WMSZ_TOPLEFT)
1544
+ rect->left = rect->right - rounded_width;
1545
+ }
1546
+
1547
+ /* Under Wine, it appears that the code to force the window size to be
1548
+ an integral number of columns and rows doesn't work. This is because
1549
+ WM_SIZING messages aren't sent (this is apparently fixed as of Wine 1.7.18,
1550
+ though I've not tried it yet; I'm still on Wine 1.6, the stable branch.)
1551
+ You can therefore end up in a loop where the code keeps trying to resize a
1552
+ window that isn't actually resizing. So, _when running in Wine only_,
1553
+ we want that code not to be executed... which means having to figure out:
1554
+ are we running under Wine? Which means that when PDCurses/WinGUI is
1555
+ initialized, we set the following 'wine_version' pointer. One could
1556
+ actually call wine_version(), if not NULL, to get the current Wine
1557
+ version. */
1558
+
1559
+ typedef const char *(CDECL *wine_version_func)(void);
1560
+
1561
+ static wine_version_func wine_version;
1562
+
1563
+ static void HandleSize( const WPARAM wParam, const LPARAM lParam)
1564
+ {
1565
+ static WPARAM prev_wParam = (WPARAM)-99;
1566
+ const unsigned n_xpixels = LOWORD (lParam);
1567
+ const unsigned n_ypixels = HIWORD (lParam);
1568
+ unsigned new_n_rows, new_n_cols;
1569
+
1570
+ debug_printf( "WM_SIZE: wParam %x %d %d %d\n", (unsigned)wParam,
1571
+ n_xpixels, n_ypixels, SP->resized);
1572
+ /* if( wine_version)
1573
+ printf( "Wine version: %s\n", wine_version( )); */
1574
+
1575
+
1576
+ if( wParam == SIZE_MINIMIZED )
1577
+ {
1578
+ prev_wParam = SIZE_MINIMIZED;
1579
+ return;
1580
+ }
1581
+ new_n_rows = n_ypixels / PDC_cyChar;
1582
+ new_n_cols = n_xpixels / PDC_cxChar;
1583
+ debug_printf( "Size was %d x %d; will be %d x %d\n",
1584
+ PDC_n_rows, PDC_n_cols, new_n_rows, new_n_cols);
1585
+ SP->resized = FALSE;
1586
+
1587
+ /* If the window will have a different number of rows */
1588
+ /* or columns, we put KEY_RESIZE in the key queue. */
1589
+ /* We don't do this if */
1590
+ /* the resizing is the result of the window being */
1591
+ /* initialized, or as a result of PDC_resize_screen */
1592
+ /* being called. In the latter case, the user */
1593
+ /* presumably already knows the screen's been resized. */
1594
+ if( PDC_n_rows != (int)new_n_rows || PDC_n_cols != (int)new_n_cols)
1595
+ {
1596
+ PDC_n_cols = new_n_cols;
1597
+ PDC_n_rows = new_n_rows;
1598
+ debug_printf( "prev_wParam = %d; add_resize_key = %d\n",
1599
+ (int)prev_wParam, add_resize_key);
1600
+ if( prev_wParam != (WPARAM)-99 && add_resize_key)
1601
+ {
1602
+ /* don't add a key when the window is initialized */
1603
+ add_key_to_queue( KEY_RESIZE);
1604
+ SP->resized = TRUE;
1605
+ }
1606
+ }
1607
+ else if( wine_version)
1608
+ return;
1609
+
1610
+ add_resize_key = 1;
1611
+ if( wParam == SIZE_RESTORED &&
1612
+ ( n_xpixels % PDC_cxChar || n_ypixels % PDC_cyChar))
1613
+ {
1614
+ int new_xpixels = PDC_cxChar * PDC_n_cols;
1615
+ int new_ypixels = PDC_cyChar * PDC_n_rows;
1616
+
1617
+ adjust_window_size( &new_xpixels, &new_ypixels,
1618
+ GetWindowLong( PDC_hWnd, GWL_STYLE), menu_shown);
1619
+ debug_printf( "Irregular size\n");
1620
+ SetWindowPos( PDC_hWnd, 0, 0, 0,
1621
+ new_xpixels, new_ypixels,
1622
+ SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
1623
+
1624
+ }
1625
+
1626
+ /* If the window has been restored from minimized form, */
1627
+ /* we should repaint. Otherwise, don't. */
1628
+ prev_wParam = wParam;
1629
+ }
1630
+
1631
+ static void HandleMouseMove( WPARAM wParam, LPARAM lParam,
1632
+ int* ptr_modified_key_to_return )
1633
+ {
1634
+ const int mouse_x = LOWORD( lParam) / PDC_cxChar;
1635
+ const int mouse_y = HIWORD( lParam) / PDC_cyChar;
1636
+ static int prev_mouse_x, prev_mouse_y;
1637
+
1638
+ if( mouse_x != prev_mouse_x || mouse_y != prev_mouse_y)
1639
+ {
1640
+ int report_event = 0;
1641
+
1642
+ prev_mouse_x = mouse_x;
1643
+ prev_mouse_y = mouse_y;
1644
+ if( wParam & MK_LBUTTON)
1645
+ {
1646
+ PDC_mouse_rect.left = mouse_x;
1647
+ PDC_mouse_rect.top = mouse_y;
1648
+ if( SP->_trap_mbe & BUTTON1_MOVED)
1649
+ report_event |= PDC_MOUSE_MOVED | 1;
1650
+ }
1651
+ if( wParam & MK_MBUTTON)
1652
+ if( SP->_trap_mbe & BUTTON2_MOVED)
1653
+ report_event |= PDC_MOUSE_MOVED | 2;
1654
+ if( wParam & MK_RBUTTON)
1655
+ if( SP->_trap_mbe & BUTTON3_MOVED)
1656
+ report_event |= PDC_MOUSE_MOVED | 4;
1657
+
1658
+ #ifdef CANT_DO_THINGS_THIS_WAY
1659
+ /* Logic would dictate the following lines. But with PDCurses */
1660
+ /* as it's currently set up, we've run out of bits and there */
1661
+ /* is no BUTTON4_MOVED or BUTTON5_MOVED. Perhaps we need to */
1662
+ /* redefine _trap_mbe to be a 64-bit quantity? */
1663
+ if( wParam & MK_XBUTTON1)
1664
+ if( SP->_trap_mbe & BUTTON4_MOVED)
1665
+ report_event |= PDC_MOUSE_MOVED | 8;
1666
+ if( wParam & MK_XBUTTON2)
1667
+ if( SP->_trap_mbe & BUTTON5_MOVED)
1668
+ report_event |= PDC_MOUSE_MOVED | 16;
1669
+ #endif
1670
+
1671
+ if( !report_event)
1672
+ if( SP->_trap_mbe & REPORT_MOUSE_POSITION)
1673
+ report_event = PDC_MOUSE_POSITION;
1674
+ if( report_event)
1675
+ {
1676
+ int i;
1677
+
1678
+ pdc_mouse_status.changes = report_event;
1679
+ for( i = 0; i < 3; i++)
1680
+ {
1681
+ pdc_mouse_status.button[i] = (((report_event >> i) & 1) ?
1682
+ BUTTON_MOVED : 0);
1683
+ }
1684
+ *ptr_modified_key_to_return = 0;
1685
+ set_mouse( -1, 0, lParam );
1686
+ } /* -1 to 'set_mouse' signals mouse move; 0 is ignored */
1687
+ }
1688
+ }
1689
+
1690
+ static void HandlePaint( HWND hwnd )
1691
+ {
1692
+ PAINTSTRUCT ps;
1693
+ HDC hdc;
1694
+ RECT rect;
1695
+
1696
+ GetUpdateRect( hwnd, &rect, FALSE);
1697
+ /* printf( "In HandlePaint: %ld %ld, %ld %ld\n",
1698
+ rect.left, rect.top, rect.right, rect.bottom); */
1699
+
1700
+ hdc = BeginPaint( hwnd, &ps);
1701
+
1702
+ fix_up_edges( hdc, &rect);
1703
+
1704
+ if( curscr && curscr->_y)
1705
+ {
1706
+ int i, x1, n_chars;
1707
+
1708
+ x1 = rect.left / PDC_cxChar;
1709
+ n_chars = rect.right / PDC_cxChar - x1 + 1;
1710
+ if( n_chars > SP->cols - x1)
1711
+ n_chars = SP->cols - x1;
1712
+ if( n_chars > 0)
1713
+ for( i = rect.top / PDC_cyChar; i <= rect.bottom / PDC_cyChar; i++)
1714
+ if( i < SP->lines && curscr->_y[i])
1715
+ PDC_transform_line_given_hdc( hdc, i, x1,
1716
+ n_chars, curscr->_y[i] + x1);
1717
+ }
1718
+ EndPaint( hwnd, &ps );
1719
+ }
1720
+
1721
+ static bool key_already_handled = FALSE;
1722
+
1723
+ static void HandleSyskeyDown( const WPARAM wParam, const LPARAM lParam,
1724
+ int *ptr_modified_key_to_return )
1725
+ {
1726
+ const int shift_pressed = (GetKeyState( VK_SHIFT) & 0x8000);
1727
+ const int ctrl_pressed = (GetKeyState( VK_CONTROL) & 0x8000);
1728
+ const int alt_pressed = (GetKeyState( VK_MENU) & 0x8000);
1729
+ const int extended = ((lParam & 0x01000000) != 0);
1730
+ const int repeated = (int)( lParam >> 30) & 1;
1731
+ const KPTAB *kptr = kptab + wParam;
1732
+ int key = 0;
1733
+ static int repeat_count;
1734
+
1735
+ if( !repeated)
1736
+ *ptr_modified_key_to_return = 0;
1737
+
1738
+ if( repeated)
1739
+ repeat_count++;
1740
+ else
1741
+ repeat_count = 0;
1742
+ if( SP->return_key_modifiers && !repeated)
1743
+ { /* See notes above this function */
1744
+ if( wParam == VK_SHIFT)
1745
+ {
1746
+ if( GetKeyState( VK_LSHIFT) & 0x8000)
1747
+ *ptr_modified_key_to_return = KEY_SHIFT_L;
1748
+ else if( GetKeyState( VK_RSHIFT) & 0x8000)
1749
+ *ptr_modified_key_to_return = KEY_SHIFT_R;
1750
+ else if(( HIWORD( lParam) & 0xff) == 0x36)
1751
+ *ptr_modified_key_to_return = KEY_SHIFT_R;
1752
+ else
1753
+ *ptr_modified_key_to_return = KEY_SHIFT_L;
1754
+ }
1755
+ if( wParam == VK_CONTROL)
1756
+ *ptr_modified_key_to_return =
1757
+ (extended ? KEY_CONTROL_R : KEY_CONTROL_L);
1758
+ if( wParam == VK_MENU)
1759
+ *ptr_modified_key_to_return =
1760
+ (extended ? KEY_ALT_R : KEY_ALT_L);
1761
+ }
1762
+
1763
+ if( !key) /* it's not a shift, ctl, alt handled above */
1764
+ {
1765
+ if( extended && kptr->extended != 999)
1766
+ kptr = ext_kptab + kptr->extended;
1767
+
1768
+ if( alt_pressed)
1769
+ key = kptr->alt;
1770
+ else if( ctrl_pressed)
1771
+ key = kptr->control;
1772
+ else if( shift_pressed)
1773
+ key = kptr->shift;
1774
+ else
1775
+ key = kptr->normal;
1776
+ }
1777
+
1778
+ /* On non-US keyboards, people hit Alt-Gr ("Alt-Ctrl" to */
1779
+ /* those on US keyboards) to get characters not otherwise */
1780
+ /* available: accented characters, local currency symbols, */
1781
+ /* etc. So we default to suppressing Alt-Ctrl-letter combos. */
1782
+ /* However, apps can set PDC_show_ctrl_alts if they know they're */
1783
+ /* running on a US keyboard layout (or other layout that doesn't */
1784
+ /* make special use of Ctrl-Alt... for example, I use the Dvorak */
1785
+ /* layout; it's fine with PDC_show_ctrl_alts = 1.) */
1786
+ if( key >= KEY_MIN && key <= KEY_MAX)
1787
+ if( !ctrl_pressed || !alt_pressed || PDC_show_ctrl_alts)
1788
+ {
1789
+ add_key_to_queue( key);
1790
+ if( wParam == VK_MULTIPLY || wParam == VK_DIVIDE
1791
+ || wParam == VK_ADD || wParam == VK_SUBTRACT
1792
+ || wParam == VK_RETURN)
1793
+ if( !alt_pressed)
1794
+ key_already_handled = TRUE;
1795
+ }
1796
+ pdc_key_modifiers = 0;
1797
+ /* Save the key modifiers if required. Do this first to allow to
1798
+ detect e.g. a pressed CTRL key after a hit of NUMLOCK. */
1799
+
1800
+ if (SP->save_key_modifiers)
1801
+ {
1802
+ if( alt_pressed)
1803
+ pdc_key_modifiers |= PDC_KEY_MODIFIER_ALT;
1804
+
1805
+ if( shift_pressed)
1806
+ pdc_key_modifiers |= PDC_KEY_MODIFIER_SHIFT;
1807
+
1808
+ if( ctrl_pressed)
1809
+ pdc_key_modifiers |= PDC_KEY_MODIFIER_CONTROL;
1810
+
1811
+ if( GetKeyState( VK_NUMLOCK) & 1)
1812
+ pdc_key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK;
1813
+
1814
+ if( repeat_count)
1815
+ pdc_key_modifiers |= PDC_KEY_MODIFIER_REPEAT;
1816
+ }
1817
+ }
1818
+
1819
+ /* Blinking text is supposed to blink twice a second. Therefore,
1820
+ HandleTimer( ) is called every .5 seconds.
1821
+
1822
+ In truth, it's not so much 'blinking' as 'changing certain types of
1823
+ text' that happens. If text is really blinking (i.e., PDC_set_blink(TRUE)
1824
+ has been called), we need to flip that text. Or if text _was_ blinking
1825
+ and we've just called PDC_set_blink(FALSE), all that text has to be
1826
+ redrawn in 'standout' mode. Also, if PDC_set_line_color() has been
1827
+ called, all text with left/right/under/over/strikeout lines needs to
1828
+ be redrawn.
1829
+
1830
+ So. After determining which attributes require redrawing (if any),
1831
+ we run through all of 'curscr' and look for text with those attributes
1832
+ set. If we find such text, we run it through PDC_transform_line.
1833
+ (To speed matters up slightly, we skip over text at the start and end
1834
+ of each line that lacks the desired attributes. We could conceivably
1835
+ get more clever; as it stands, if the very first and very last
1836
+ characters are blinking, we redraw the entire line, even though
1837
+ everything in between may not require it. But it would probably be a
1838
+ lot of code for little benefit.)
1839
+
1840
+ Note that by default, we'll usually find that the line color hasn't
1841
+ changed and the 'blink mode' is still FALSE. In that case, attr_to_seek
1842
+ will be zero and the only thing we'll do here is to blink the cursor. */
1843
+
1844
+ static void HandleTimer( const WPARAM wParam )
1845
+ {
1846
+ int i; /* see WndProc() notes */
1847
+ extern int PDC_really_blinking; /* see 'pdcsetsc.c' */
1848
+ static int previously_really_blinking = 0;
1849
+ static int prev_line_color = -1;
1850
+ chtype attr_to_seek = 0;
1851
+
1852
+ if( prev_line_color != SP->line_color)
1853
+ attr_to_seek = A_ALL_LINES;
1854
+ if( PDC_really_blinking || previously_really_blinking)
1855
+ attr_to_seek |= A_BLINK;
1856
+ prev_line_color = SP->line_color;
1857
+ previously_really_blinking = PDC_really_blinking;
1858
+ PDC_blink_state ^= 1;
1859
+ if( attr_to_seek)
1860
+ {
1861
+ for( i = 0; i < SP->lines; i++)
1862
+ {
1863
+ if( curscr->_y[i])
1864
+ {
1865
+ int j = 0, n_chars;
1866
+ chtype *line = curscr->_y[i];
1867
+
1868
+ /* skip over starting text that isn't blinking: */
1869
+ while( j < SP->cols && !(*line & attr_to_seek))
1870
+ {
1871
+ j++;
1872
+ line++;
1873
+ }
1874
+ n_chars = SP->cols - j;
1875
+ /* then skip over text at the end that's not blinking: */
1876
+ while( n_chars && !(line[n_chars - 1] & attr_to_seek))
1877
+ {
1878
+ n_chars--;
1879
+ }
1880
+ if( n_chars)
1881
+ PDC_transform_line( i, j, n_chars, line);
1882
+ }
1883
+ /* else
1884
+ MessageBox( 0, "NULL _y[] found\n", "PDCurses", MB_OK); */
1885
+ }
1886
+ }
1887
+ if( SP->cursrow >=SP->lines || SP->curscol >= SP->cols
1888
+ || SP->cursrow < 0 || SP->curscol < 0
1889
+ || !curscr->_y || !curscr->_y[SP->cursrow])
1890
+ debug_printf( "Cursor off-screen: %d %d, %d %d\n",
1891
+ SP->cursrow, SP->curscol, SP->lines, SP->cols);
1892
+ else if( PDC_CURSOR_IS_BLINKING)
1893
+ PDC_transform_line( SP->cursrow, SP->curscol, 1,
1894
+ curscr->_y[SP->cursrow] + SP->curscol);
1895
+ }
1896
+
1897
+ /* Options to enlarge/shrink the font are currently commented out. */
1898
+
1899
+ static HMENU set_menu( void)
1900
+ {
1901
+ const HMENU hMenu = CreateMenu( );
1902
+ #ifdef PDC_WIDE
1903
+ AppendMenu( hMenu, MF_STRING, WM_CHOOSE_FONT, L"Font");
1904
+ AppendMenu( hMenu, MF_STRING, WM_PASTE, L"Paste");
1905
+ #else
1906
+ AppendMenu( hMenu, MF_STRING, WM_CHOOSE_FONT, "Font");
1907
+ AppendMenu( hMenu, MF_STRING, WM_PASTE, "Paste");
1908
+ #endif
1909
+ return( hMenu);
1910
+ }
1911
+
1912
+ INLINE void HandleMenuToggle( bool *ptr_ignore_resize)
1913
+ {
1914
+ const bool is_zoomed = IsZoomed( PDC_hWnd);
1915
+ HMENU hMenu;
1916
+
1917
+ menu_shown ^= 1;
1918
+ hMenu = GetSystemMenu( PDC_hWnd, FALSE);
1919
+ CheckMenuItem( hMenu, WM_TOGGLE_MENU, MF_BYCOMMAND
1920
+ | (menu_shown ? MF_CHECKED : MF_UNCHECKED));
1921
+
1922
+ if( !is_zoomed)
1923
+ *ptr_ignore_resize = TRUE;
1924
+ if( !menu_shown)
1925
+ {
1926
+ hMenu = GetMenu( PDC_hWnd); /* destroy existing menu */
1927
+ DestroyMenu( hMenu);
1928
+ hMenu = CreateMenu( ); /* then set an empty menu */
1929
+ SetMenu( PDC_hWnd, hMenu);
1930
+ }
1931
+ else
1932
+ {
1933
+ SetMenu( PDC_hWnd, set_menu( ));
1934
+ }
1935
+ *ptr_ignore_resize = FALSE;
1936
+
1937
+ if( !is_zoomed)
1938
+ {
1939
+ PDC_resize_screen( PDC_n_rows, PDC_n_cols );
1940
+ }
1941
+
1942
+ InvalidateRect( PDC_hWnd, NULL, FALSE);
1943
+ }
1944
+
1945
+ INLINE uint64_t milliseconds_since_1970( void)
1946
+ {
1947
+ FILETIME ft;
1948
+ const uint64_t jd_1601 = 2305813; /* actually 2305813.5 */
1949
+ const uint64_t jd_1970 = 2440587; /* actually 2440587.5 */
1950
+ const uint64_t ten_million = 10000000;
1951
+ const uint64_t diff = (jd_1970 - jd_1601) * ten_million * 86400;
1952
+ uint64_t decimicroseconds_since_1970; /* i.e., time in units of 1e-7 seconds */
1953
+
1954
+ GetSystemTimeAsFileTime( &ft);
1955
+ decimicroseconds_since_1970 = ((uint64_t)ft.dwLowDateTime |
1956
+ ((uint64_t)ft.dwHighDateTime << 32)) - diff;
1957
+ return( decimicroseconds_since_1970 / 10000);
1958
+ }
1959
+
1960
+ /* Note that there are two types of WM_TIMER timer messages. One type
1961
+ indicates that SP->mouse_wait milliseconds have elapsed since a mouse
1962
+ button was pressed; that's handled as described in the above notes.
1963
+ The other type, issued every half second, indicates that blinking
1964
+ should take place. For these, HandleTimer() is called (see above).
1965
+
1966
+ On WM_PAINT, we determine what parts of 'curscr' would be covered by
1967
+ the update rectangle, and run those through PDC_transform_line.
1968
+
1969
+ For determining left/right shift, alt, and control, I borrowed code
1970
+ from SDL. Note that the Win32 version of PDCurses doesn't work correctly
1971
+ here for Win9x; it just does GetKeyState( VK_LSHIFT), etc., which is
1972
+ apparently not supported in Win9x. So no matter which shift (or alt or
1973
+ Ctrl key) is hit, the right-hand variant is returned in that library.
1974
+ The SDL handling, and hence the handling below, _does_ work on Win9x.
1975
+ Note, though, that in Win9x, detection of the Shift keys is hardware
1976
+ dependent; if you've an unusual keyboard, both Shift keys may be
1977
+ detected as right, or both as left. */
1978
+
1979
+ #if defined(_WIN32) && defined(__GNUC__)
1980
+ #define ALIGN_STACK __attribute__((force_align_arg_pointer))
1981
+ #else
1982
+ #define ALIGN_STACK
1983
+ #endif
1984
+
1985
+ static LRESULT ALIGN_STACK CALLBACK WndProc (const HWND hwnd,
1986
+ const UINT message,
1987
+ const WPARAM wParam,
1988
+ const LPARAM lParam)
1989
+ {
1990
+ int button_down = -1, button_up = -1;
1991
+ static int mouse_buttons_pressed = 0;
1992
+ static LPARAM mouse_lParam;
1993
+ static uint64_t last_click_time[PDC_MAX_MOUSE_BUTTONS];
1994
+ /* in millisec since 1970 */
1995
+ static int modified_key_to_return = 0;
1996
+ const RECT before_rect = PDC_mouse_rect;
1997
+ static bool ignore_resize = FALSE;
1998
+
1999
+ PDC_hWnd = hwnd;
2000
+ if( !hwnd)
2001
+ debug_printf( "Null hWnd: msg %u, wParam %x, lParam %lx\n",
2002
+ message, wParam, lParam);
2003
+
2004
+ switch (message)
2005
+ {
2006
+ case WM_SIZING:
2007
+ HandleSizing( wParam, lParam );
2008
+ return( TRUE );
2009
+
2010
+ case WM_SIZE:
2011
+ /* If ignore_resize = 1, don't bother resizing; */
2012
+ /* the final window size has yet to be set */
2013
+ if( ignore_resize == FALSE)
2014
+ HandleSize( wParam, lParam);
2015
+ return 0 ;
2016
+
2017
+ case WM_MOUSEWHEEL:
2018
+ debug_printf( "Mouse wheel: %x %lx\n", wParam, lParam);
2019
+ modified_key_to_return = 0;
2020
+ set_mouse( VERTICAL_WHEEL_EVENT, (short)( HIWORD(wParam)), lParam);
2021
+ break;
2022
+
2023
+ case WM_MOUSEHWHEEL:
2024
+ debug_printf( "Mouse horiz wheel: %x %lx\n", wParam, lParam);
2025
+ modified_key_to_return = 0;
2026
+ set_mouse( HORIZONTAL_WHEEL_EVENT, (short)( HIWORD(wParam)), lParam);
2027
+ break;
2028
+
2029
+ case WM_MOUSEMOVE:
2030
+ HandleMouseMove( wParam, lParam, &modified_key_to_return );
2031
+ break;
2032
+
2033
+ case WM_LBUTTONDOWN:
2034
+ PDC_mouse_rect.left = PDC_mouse_rect.right =
2035
+ LOWORD( lParam) / PDC_cxChar;
2036
+ PDC_mouse_rect.top = PDC_mouse_rect.bottom =
2037
+ HIWORD( lParam) / PDC_cyChar;
2038
+ PDC_selecting_rectangle = (wParam & MK_SHIFT);
2039
+ SetCapture( hwnd);
2040
+ button_down = 0;
2041
+ break;
2042
+
2043
+ case WM_LBUTTONUP:
2044
+ button_up = 0;
2045
+ ReleaseCapture( );
2046
+ if( (PDC_mouse_rect.left != PDC_mouse_rect.right ||
2047
+ PDC_mouse_rect.top != PDC_mouse_rect.bottom) &&
2048
+ (PDC_mouse_rect.right >= 0 && PDC_mouse_rect.left >= 0
2049
+ && curscr && curscr->_y) )
2050
+ {
2051
+ /* RR: will crash sometimes */
2052
+ /* As an example on double-click of the title bar */
2053
+ HandleBlockCopy();
2054
+ }
2055
+ PDC_mouse_rect.top = PDC_mouse_rect.bottom = -1; /* now hide rect */
2056
+ break;
2057
+
2058
+ case WM_RBUTTONDOWN:
2059
+ button_down = 2;
2060
+ SetCapture( hwnd);
2061
+ break;
2062
+
2063
+ case WM_RBUTTONUP:
2064
+ button_up = 2;
2065
+ ReleaseCapture( );
2066
+ break;
2067
+
2068
+ case WM_MBUTTONDOWN:
2069
+ button_down = 1;
2070
+ SetCapture( hwnd);
2071
+ break;
2072
+
2073
+ case WM_MBUTTONUP:
2074
+ button_up = 1;
2075
+ ReleaseCapture( );
2076
+ break;
2077
+
2078
+ #if( PDC_MAX_MOUSE_BUTTONS >= 5)
2079
+ /* WinGUI can support five mouse buttons. But some may wish */
2080
+ /* to leave PDC_MAX_MOUSE_BUTTONS=3, for compatibility */
2081
+ /* with older PDCurses libraries. Hence the above #if. */
2082
+ case WM_XBUTTONDOWN:
2083
+ button_down = ((wParam & MK_XBUTTON1) ? 3 : 4);
2084
+ SetCapture( hwnd);
2085
+ break;
2086
+
2087
+ case WM_XBUTTONUP:
2088
+ #ifdef WRONG_WAY
2089
+ /* You'd think we'd use the following line, wouldn't you? */
2090
+ /* But we can't, because an XBUTTONUP message doesn't actually */
2091
+ /* tell you which button was released! So we'll assume that */
2092
+ /* the released xbutton matches a pressed one; and we've kept */
2093
+ /* track of which buttons are currently pressed. */
2094
+ button_up = ((wParam & MK_XBUTTON1) ? 3 : 4);
2095
+ #endif
2096
+ button_up = (((mouse_buttons_pressed & 8) ||
2097
+ pdc_mouse_status.xbutton[0] & BUTTON_PRESSED) ? 3 : 4);
2098
+ ReleaseCapture( );
2099
+ break;
2100
+ #endif /* #if( PDC_MAX_MOUSE_BUTTONS >= 5) */
2101
+
2102
+ case WM_MOVE:
2103
+ return 0 ;
2104
+
2105
+ case WM_ERASEBKGND: /* no need to erase background; it'll */
2106
+ return( 0); /* all get painted over anyway */
2107
+
2108
+ /* The WM_PAINT routine is sort of "borrowed" from doupdate( ) from */
2109
+ /* refresh.c. I'm not entirely sure that this is what ought to be */
2110
+ /* done, though it does appear to work correctly. */
2111
+ case WM_PAINT:
2112
+ if( hwnd && curscr )
2113
+ {
2114
+ HandlePaint( hwnd );
2115
+ }
2116
+ break;
2117
+
2118
+ case WM_KEYUP:
2119
+ case WM_SYSKEYUP:
2120
+ if( wParam == VK_MENU && numpad_unicode_value)
2121
+ {
2122
+ modified_key_to_return = numpad_unicode_value;
2123
+ numpad_unicode_value = 0;
2124
+ pdc_key_modifiers = 0;
2125
+ }
2126
+ if( modified_key_to_return )
2127
+ {
2128
+ add_key_to_queue( modified_key_to_return );
2129
+ modified_key_to_return = 0;
2130
+ }
2131
+ break;
2132
+
2133
+ case WM_CHAR: /* _Don't_ add Shift-Tab; it's handled elsewhere */
2134
+ if( wParam != 9 || !(GetKeyState( VK_SHIFT) & 0x8000))
2135
+ if( !key_already_handled)
2136
+ add_key_to_queue( (int)wParam );
2137
+ key_already_handled = FALSE;
2138
+ break;
2139
+
2140
+ case WM_KEYDOWN:
2141
+ case WM_SYSKEYDOWN:
2142
+ if( wParam < 225 && wParam > 0 )
2143
+ {
2144
+ HandleSyskeyDown( wParam, lParam, &modified_key_to_return );
2145
+ }
2146
+ return 0 ;
2147
+
2148
+ case WM_SYSCHAR:
2149
+ return 0 ;
2150
+
2151
+ case WM_TIMER:
2152
+ /* see notes above this function */
2153
+ if( wParam != TIMER_ID_FOR_BLINKING )
2154
+ {
2155
+ static const int remap_table[PDC_MAX_MOUSE_BUTTONS] =
2156
+ { BUTTON1_PRESSED, BUTTON2_PRESSED, BUTTON3_PRESSED,
2157
+ BUTTON4_PRESSED, BUTTON5_PRESSED };
2158
+
2159
+ modified_key_to_return = 0;
2160
+ if( SP && (SP->_trap_mbe & remap_table[wParam]))
2161
+ set_mouse( (const int) wParam, BUTTON_PRESSED, mouse_lParam);
2162
+ KillTimer( PDC_hWnd, (int)wParam);
2163
+ mouse_buttons_pressed ^= (1 << wParam);
2164
+ }
2165
+ else if( SP && curscr && curscr->_y)
2166
+ {
2167
+ /* blink the blinking text */
2168
+ HandleTimer( wParam );
2169
+ }
2170
+ break;
2171
+
2172
+ case WM_CLOSE:
2173
+ {
2174
+ if( !PDC_shutdown_key[FUNCTION_KEY_SHUT_DOWN])
2175
+ {
2176
+ final_cleanup( );
2177
+ PDC_bDone = TRUE;
2178
+ exit( 0);
2179
+ }
2180
+ else
2181
+ add_key_to_queue( PDC_shutdown_key[FUNCTION_KEY_SHUT_DOWN]);
2182
+ }
2183
+ return( 0);
2184
+
2185
+ case WM_COMMAND:
2186
+ case WM_SYSCOMMAND:
2187
+ if( wParam == WM_EXIT_GRACELESSLY)
2188
+ {
2189
+ final_cleanup( );
2190
+ PDC_bDone = TRUE;
2191
+ exit( 0);
2192
+ }
2193
+ else if( wParam == WM_ENLARGE_FONT || wParam == WM_SHRINK_FONT)
2194
+ {
2195
+ adjust_font_size( (wParam == WM_ENLARGE_FONT) ? 1 : -1);
2196
+ return( 0);
2197
+ }
2198
+ else if( wParam == WM_CHOOSE_FONT)
2199
+ {
2200
+ if( PDC_choose_a_new_font( ))
2201
+ adjust_font_size( 0);
2202
+ return( 0);
2203
+ }
2204
+ else if( wParam == WM_PASTE)
2205
+ {
2206
+ PDC_add_clipboard_to_key_queue( );
2207
+ }
2208
+ else if( wParam == WM_TOGGLE_MENU)
2209
+ {
2210
+ HandleMenuToggle( &ignore_resize);
2211
+ }
2212
+ break;
2213
+
2214
+ case WM_DESTROY:
2215
+ PDC_LOG(("WM_DESTROY\n"));
2216
+ PostQuitMessage (0) ;
2217
+ PDC_bDone = TRUE;
2218
+ return 0 ;
2219
+ }
2220
+
2221
+ if( hwnd)
2222
+ show_mouse_rect( hwnd, before_rect, PDC_mouse_rect);
2223
+
2224
+ if( button_down >= 0)
2225
+ {
2226
+ modified_key_to_return = 0;
2227
+ SetTimer( hwnd, button_down, SP->mouse_wait, NULL);
2228
+ mouse_buttons_pressed |= (1 << button_down);
2229
+ mouse_lParam = lParam;
2230
+ }
2231
+ if( button_up >= 0)
2232
+ {
2233
+ int message_to_send = -1;
2234
+
2235
+ modified_key_to_return = 0;
2236
+ if( (mouse_buttons_pressed >> button_up) & 1)
2237
+ {
2238
+ const uint64_t curr_click_time =
2239
+ milliseconds_since_1970( );
2240
+ static const int double_remap_table[PDC_MAX_MOUSE_BUTTONS] =
2241
+ { BUTTON1_DOUBLE_CLICKED, BUTTON2_DOUBLE_CLICKED,
2242
+ BUTTON3_DOUBLE_CLICKED, BUTTON4_DOUBLE_CLICKED,
2243
+ BUTTON5_DOUBLE_CLICKED };
2244
+ static const int triple_remap_table[PDC_MAX_MOUSE_BUTTONS] =
2245
+ { BUTTON1_TRIPLE_CLICKED, BUTTON2_TRIPLE_CLICKED,
2246
+ BUTTON3_TRIPLE_CLICKED, BUTTON4_TRIPLE_CLICKED,
2247
+ BUTTON5_TRIPLE_CLICKED };
2248
+ static int n_previous_clicks;
2249
+
2250
+ if( curr_click_time <
2251
+ last_click_time[button_up] + 2 * SP->mouse_wait)
2252
+ n_previous_clicks++; /* 'n_previous_clicks' will be */
2253
+ else /* zero for a "normal" click, 1 */
2254
+ n_previous_clicks = 0; /* for a dblclick, 2 for a triple */
2255
+
2256
+ if( n_previous_clicks >= 2 &&
2257
+ (SP->_trap_mbe & triple_remap_table[button_up]))
2258
+ message_to_send = BUTTON_TRIPLE_CLICKED;
2259
+ else if( n_previous_clicks >= 1 &&
2260
+ (SP->_trap_mbe & double_remap_table[button_up]))
2261
+ message_to_send = BUTTON_DOUBLE_CLICKED;
2262
+ else /* either it's not a doubleclick, or we aren't */
2263
+ { /* checking for double clicks */
2264
+ static const int remap_table[PDC_MAX_MOUSE_BUTTONS] =
2265
+ { BUTTON1_CLICKED, BUTTON2_CLICKED, BUTTON3_CLICKED,
2266
+ BUTTON4_CLICKED, BUTTON5_CLICKED };
2267
+
2268
+ if( SP->_trap_mbe & remap_table[button_up])
2269
+ message_to_send = BUTTON_CLICKED;
2270
+ }
2271
+ KillTimer( hwnd, button_up);
2272
+ mouse_buttons_pressed ^= (1 << button_up);
2273
+ last_click_time[button_up] = curr_click_time;
2274
+ }
2275
+ if( message_to_send == -1) /* might just send as a 'released' msg */
2276
+ {
2277
+ static const int remap_table[PDC_MAX_MOUSE_BUTTONS] =
2278
+ { BUTTON1_RELEASED, BUTTON2_RELEASED, BUTTON3_RELEASED,
2279
+ BUTTON4_RELEASED, BUTTON5_RELEASED };
2280
+
2281
+ if( SP->_trap_mbe & remap_table[button_up])
2282
+ message_to_send = BUTTON_RELEASED;
2283
+ }
2284
+ if( message_to_send != -1)
2285
+ set_mouse( button_up, message_to_send, lParam);
2286
+ }
2287
+
2288
+ return DefWindowProc( hwnd, message, wParam, lParam) ;
2289
+ }
2290
+
2291
+ /* Default behaviour is that, when one clicks on the 'close' button, */
2292
+ /* exit( 0) is called, just as in the SDL and X11 versions. But if */
2293
+ /* one wishes, one can call PDC_set_shutdown_key to cause those */
2294
+ /* buttons to put a specified character into the input queue. It's */
2295
+ /* then the application's problem to exit gracefully, perhaps with */
2296
+ /* messages such as 'are you sure' and so forth. */
2297
+ /* If you've set a shutdown key, there's always a risk that the */
2298
+ /* program will get stuck in a loop and never process said key. So */
2299
+ /* when the key is set, a 'Kill' item is appended to the system menu */
2300
+ /* so that the user still has some way to terminate the app, albeit */
2301
+ /* with extreme prejudice (i.e., click on 'Kill' and exit is called */
2302
+ /* and the app exits gracelessly.) */
2303
+
2304
+ int PDC_set_function_key( const unsigned function, const int new_key)
2305
+ {
2306
+ int old_key = -1;
2307
+
2308
+ if( function < PDC_MAX_FUNCTION_KEYS)
2309
+ {
2310
+ old_key = PDC_shutdown_key[function];
2311
+ PDC_shutdown_key[function] = new_key;
2312
+ }
2313
+
2314
+ if( function == FUNCTION_KEY_SHUT_DOWN)
2315
+ if( (new_key && !old_key) || (old_key && !new_key))
2316
+ {
2317
+ HMENU hMenu = GetSystemMenu( PDC_hWnd, FALSE);
2318
+
2319
+ if( new_key)
2320
+ AppendMenu( hMenu, MF_STRING, WM_EXIT_GRACELESSLY, _T( "Kill"));
2321
+ else
2322
+ RemoveMenu( hMenu, WM_EXIT_GRACELESSLY, MF_BYCOMMAND);
2323
+ }
2324
+ return( old_key);
2325
+ }
2326
+
2327
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/dd162826(v=vs.85).aspx
2328
+ The code at the above link provides general methods for positioning a window
2329
+ on a multiple-display setup. The only instance we're using is the
2330
+ MONITOR_WORKAREA one, which ensures that even if monitor geometry changes,
2331
+ the window will still be entirely on-screen.
2332
+
2333
+ These functions entered the Win32 API with Windows 2000. If
2334
+ MONITOR_DEFAULTTONEAREST isn't defined, we shouldn't try to do this. */
2335
+
2336
+ #ifdef MONITOR_DEFAULTTONEAREST
2337
+
2338
+ static void clip_or_center_rect_to_monitor( LPRECT prc)
2339
+ {
2340
+ HMONITOR hMonitor;
2341
+ MONITORINFO mi;
2342
+ RECT rc;
2343
+ const int w = prc->right - prc->left;
2344
+ const int h = prc->bottom - prc->top;
2345
+
2346
+ hMonitor = MonitorFromRect(prc, MONITOR_DEFAULTTONEAREST);
2347
+
2348
+ mi.cbSize = sizeof(mi);
2349
+ GetMonitorInfo(hMonitor, &mi);
2350
+
2351
+ rc = mi.rcMonitor;
2352
+
2353
+ prc->left = max(rc.left, min(rc.right-w, prc->left));
2354
+ prc->top = max(rc.top, min(rc.bottom-h, prc->top));
2355
+ prc->right = prc->left + w;
2356
+ prc->bottom = prc->top + h;
2357
+ }
2358
+
2359
+ static void clip_or_center_window_to_monitor( HWND hwnd)
2360
+ {
2361
+ RECT rc;
2362
+
2363
+ GetWindowRect(hwnd, &rc);
2364
+ clip_or_center_rect_to_monitor(&rc);
2365
+ SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
2366
+ }
2367
+ #endif
2368
+
2369
+ /* By default, the user cannot resize the window. This is because
2370
+ many apps don't handle KEY_RESIZE, and one can get odd behavior
2371
+ in such cases. There are two ways around this. If you call
2372
+ PDC_set_resize_limits( ) before initwin( ), telling WinGUI exactly how
2373
+ large/small the window can be, the window will be user-resizable. Or
2374
+ you can set ttytype[0...3] to contain the resize limits. A call such as
2375
+
2376
+ PDC_set_resize_limits( 42, 42, 135, 135);
2377
+
2378
+ will result in the window being fixed at 42 lines by 135 columns.
2379
+
2380
+ PDC_set_resize_limits( 20, 50, 70, 200);
2381
+
2382
+ will mean the window can have 20 to 50 lines and 70 to 200 columns.
2383
+ The user will be able to resize the window freely within those limits.
2384
+ See 'newtest.c' (in the 'demos' folder) for an example.
2385
+
2386
+ This function is used in only one place (PDC_scr_open( )), so
2387
+ it's inlined. */
2388
+
2389
+ INLINE int set_up_window( void)
2390
+ {
2391
+ /* create the dialog window */
2392
+ WNDCLASS wndclass ;
2393
+ HMENU hMenu;
2394
+ HANDLE hInstance = GetModuleHandleA( NULL);
2395
+ int n_default_columns = 80;
2396
+ int n_default_rows = 25;
2397
+ int xsize, ysize, window_style;
2398
+ int xloc = CW_USEDEFAULT;
2399
+ int yloc = CW_USEDEFAULT;
2400
+ TCHAR WindowTitle[MAX_PATH];
2401
+ const TCHAR *AppName = _T( "Curses_App");
2402
+ HICON icon;
2403
+ static bool wndclass_has_been_registered = FALSE;
2404
+
2405
+ if( !hInstance)
2406
+ debug_printf( "No instance: %d\n", GetLastError( ));
2407
+ originally_focussed_window = GetForegroundWindow( );
2408
+ debug_printf( "hInstance %x\nOriginal window %x\n", hInstance, originally_focussed_window);
2409
+ /* set the window icon from the icon in the process */
2410
+ icon = get_app_icon();
2411
+ if( !icon )
2412
+ icon = LoadIcon( NULL, IDI_APPLICATION);
2413
+ if( !wndclass_has_been_registered)
2414
+ {
2415
+ ATOM rval;
2416
+
2417
+ wndclass.style = CS_VREDRAW ;
2418
+ wndclass.lpfnWndProc = WndProc ;
2419
+ wndclass.cbClsExtra = 0 ;
2420
+ wndclass.cbWndExtra = 0 ;
2421
+ wndclass.hInstance = hInstance ;
2422
+ wndclass.hIcon = icon;
2423
+ wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
2424
+ wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
2425
+ wndclass.lpszMenuName = NULL ;
2426
+ wndclass.lpszClassName = AppName ;
2427
+
2428
+ rval = RegisterClass( &wndclass) ;
2429
+ if( !rval)
2430
+ {
2431
+ const DWORD last_error = GetLastError( );
2432
+
2433
+ debug_printf( "RegisterClass failed: GetLastError = %lx\n", last_error);
2434
+ return( -1);
2435
+ }
2436
+ wndclass_has_been_registered = TRUE;
2437
+ }
2438
+
2439
+ get_app_name( WindowTitle, MAX_PATH, TRUE);
2440
+ #ifdef PDC_WIDE
2441
+ debug_printf( "WindowTitle = '%ls'\n", WindowTitle);
2442
+ #endif
2443
+
2444
+ get_default_sizes_from_registry( &n_default_columns, &n_default_rows, &xloc, &yloc,
2445
+ &menu_shown);
2446
+ if( PDC_n_rows > 2 && PDC_n_cols > 2)
2447
+ {
2448
+ n_default_columns = PDC_n_cols;
2449
+ n_default_rows = PDC_n_rows;
2450
+ }
2451
+ if( ttytype[1])
2452
+ PDC_set_resize_limits( (unsigned char)ttytype[0],
2453
+ (unsigned char)ttytype[1],
2454
+ (unsigned char)ttytype[2],
2455
+ (unsigned char)ttytype[3]);
2456
+ debug_printf( "Size %d x %d, loc %d x %d; menu %d\n",
2457
+ n_default_columns, n_default_rows, xloc, yloc, menu_shown);
2458
+ get_character_sizes( NULL, &PDC_cxChar, &PDC_cyChar);
2459
+
2460
+ if( min_lines != max_lines || min_cols != max_cols)
2461
+ window_style = ((n_default_columns == -1) ?
2462
+ WS_MAXIMIZE | WS_OVERLAPPEDWINDOW : WS_OVERLAPPEDWINDOW);
2463
+ else /* fixed-size window: looks "normal", but w/o a maximize box */
2464
+ window_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
2465
+
2466
+ if( n_default_columns == -1)
2467
+ xsize = ysize = CW_USEDEFAULT;
2468
+ else
2469
+ {
2470
+ keep_size_within_bounds( &n_default_rows, &n_default_columns);
2471
+ xsize = PDC_cxChar * n_default_columns;
2472
+ ysize = PDC_cyChar * n_default_rows;
2473
+ adjust_window_size( &xsize, &ysize, window_style, menu_shown);
2474
+ }
2475
+
2476
+ PDC_hWnd = CreateWindow( AppName, WindowTitle, window_style,
2477
+ xloc, yloc,
2478
+ xsize, ysize,
2479
+ NULL, (menu_shown ? set_menu( ) : NULL),
2480
+ hInstance, NULL) ;
2481
+
2482
+ if( !PDC_hWnd)
2483
+ {
2484
+ const DWORD last_error = GetLastError( );
2485
+
2486
+ debug_printf( "CreateWindow failed; GetLastError = %ld", last_error);
2487
+ return( -2);
2488
+ }
2489
+
2490
+ hMenu = GetSystemMenu( PDC_hWnd, FALSE);
2491
+ AppendMenu( hMenu, MF_STRING | (menu_shown ? MF_CHECKED : MF_UNCHECKED), WM_TOGGLE_MENU, _T( "Menu"));
2492
+ AppendMenu( hMenu, MF_STRING, WM_CHOOSE_FONT, _T( "Choose Font"));
2493
+
2494
+ debug_printf( "menu set\n");
2495
+
2496
+ ShowWindow (PDC_hWnd,
2497
+ (n_default_columns == -1) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
2498
+ debug_printf( "window shown\n");
2499
+ ValidateRect( PDC_hWnd, NULL); /* don't try repainting */
2500
+ UpdateWindow (PDC_hWnd) ;
2501
+ debug_printf( "window updated\n");
2502
+ SetTimer( PDC_hWnd, TIMER_ID_FOR_BLINKING, 500, NULL);
2503
+ debug_printf( "timer set\n");
2504
+
2505
+ #ifdef MONITOR_DEFAULTTONEAREST
2506
+ /* if the window is off-screen, move it on screen. */
2507
+ clip_or_center_window_to_monitor( PDC_hWnd);
2508
+ #endif
2509
+
2510
+ return( 0);
2511
+ }
2512
+
2513
+ /* open the physical screen -- allocate SP, miscellaneous intialization,
2514
+ and may save the existing screen for later restoration.
2515
+
2516
+ Deciding on a for-real maximum screen size has proven difficult.
2517
+ But there is really no particularly good reason to set such a maximum.
2518
+ If one does, you get some tricky issues: suppose the user drags the
2519
+ window to create a screen larger than MAX_LINES or MAX_COLUMNS? My
2520
+ hope is to evade that problem by just setting those constants to be...
2521
+ well... unrealistically large. */
2522
+
2523
+ #define MAX_LINES 50000
2524
+ #define MAX_COLUMNS 50000
2525
+
2526
+ int PDC_scr_open( int argc, char **argv)
2527
+ {
2528
+ int i, r, g, b;
2529
+ HMODULE hntdll = GetModuleHandle( _T("ntdll.dll"));
2530
+
2531
+ if( hntdll)
2532
+ wine_version = (wine_version_func)GetProcAddress(hntdll, "wine_get_version");
2533
+
2534
+ PDC_LOG(("PDC_scr_open() - called\n"));
2535
+ SP = calloc(1, sizeof(SCREEN));
2536
+ color_pair_indices = (short *)calloc(PDC_COLOR_PAIRS * 2, sizeof( short));
2537
+ pdc_rgbs = (COLORREF *)calloc(N_COLORS, sizeof( COLORREF));
2538
+ if (!SP || !color_pair_indices || !pdc_rgbs)
2539
+ return ERR;
2540
+
2541
+ debug_printf( "colors alloc\n");
2542
+ COLORS = N_COLORS; /* should give this a try and see if it works! */
2543
+ for( i = 0; i < 16; i++)
2544
+ {
2545
+ const int intensity = ((i & 8) ? 0xff : 0xc0);
2546
+
2547
+ pdc_rgbs[i] = RGB( ((i & COLOR_RED) ? intensity : 0),
2548
+ ((i & COLOR_GREEN) ? intensity : 0),
2549
+ ((i & COLOR_BLUE) ? intensity : 0));
2550
+ }
2551
+ /* 256-color xterm extended palette: 216 colors in a
2552
+ 6x6x6 color cube, plus 24 (not 50) shades of gray */
2553
+ for( r = 0; r < 6; r++)
2554
+ for( g = 0; g < 6; g++)
2555
+ for( b = 0; b < 6; b++)
2556
+ pdc_rgbs[i++] = RGB( r ? r * 40 + 55 : 0,
2557
+ g ? g * 40 + 55 : 0,
2558
+ b ? b * 40 + 55 : 0);
2559
+ for( i = 0; i < 24; i++)
2560
+ pdc_rgbs[i + 232] = RGB( i * 10 + 8, i * 10 + 8, i * 10 + 8);
2561
+ SP->mouse_wait = PDC_CLICK_PERIOD;
2562
+ SP->visibility = 0; /* no cursor, by default */
2563
+ SP->curscol = SP->cursrow = 0;
2564
+ SP->audible = TRUE;
2565
+ SP->mono = FALSE;
2566
+
2567
+ /* note: we parse the non-wide argc (see comment in header),
2568
+ therefore using non-wide char handling here */
2569
+ if( argc && argv) /* store a copy of the input arguments */
2570
+ {
2571
+ PDC_argc = argc;
2572
+ PDC_argv = (char **)calloc( argc + 1, sizeof( char *));
2573
+ for( i = 0; i < argc; i++)
2574
+ {
2575
+ PDC_argv[i] = (char *)malloc( strlen( argv[i]) + 1);
2576
+ strcpy( PDC_argv[i], argv[i]);
2577
+ }
2578
+ }
2579
+
2580
+ if( set_up_window( ))
2581
+ {
2582
+ fprintf( stderr, "set_up_window failed\n");
2583
+ return ERR;
2584
+ }
2585
+ debug_printf( "Back from set_up_window\n");
2586
+ while( !PDC_get_rows( )) /* wait for screen to be drawn and */
2587
+ ; /* actual size to be determined */
2588
+
2589
+ debug_printf( "Back from PDC_get_rows\n");
2590
+ SP->lines = PDC_get_rows();
2591
+ SP->cols = PDC_get_columns();
2592
+
2593
+ if (SP->lines < 2 || SP->lines > MAX_LINES
2594
+ || SP->cols < 2 || SP->cols > MAX_COLUMNS)
2595
+ {
2596
+ fprintf(stderr, "LINES value must be >= 2 and <= %d: got %d\n",
2597
+ MAX_LINES, SP->lines);
2598
+ fprintf(stderr, "COLS value must be >= 2 and <= %d: got %d\n",
2599
+ MAX_COLUMNS, SP->cols);
2600
+
2601
+ return ERR;
2602
+ }
2603
+
2604
+ /* PDC_reset_prog_mode(); doesn't do anything anyway */
2605
+ debug_printf( "...we're done\n");
2606
+ return OK;
2607
+ }
2608
+
2609
+ /* the core of resize_term() */
2610
+
2611
+ int PDC_resize_screen( int nlines, int ncols)
2612
+ {
2613
+ if( !stdscr) /* window hasn't been created yet; we're */
2614
+ { /* specifying its size before doing so */
2615
+ PDC_n_rows = nlines;
2616
+ PDC_n_cols = ncols;
2617
+ return OK;
2618
+ }
2619
+ SP->resized = FALSE;
2620
+ debug_printf( "Incoming: %d %d\n", nlines, ncols);
2621
+ if( nlines >= 2 && ncols >= 2 && PDC_cxChar && PDC_cyChar && PDC_hWnd &&
2622
+ !IsZoomed( PDC_hWnd) /* && WaitResult == WAIT_OBJECT_0 */)
2623
+ {
2624
+ RECT rect, client_rect;
2625
+ int new_width;
2626
+ int new_height;
2627
+
2628
+ GetWindowRect( PDC_hWnd, &rect);
2629
+ GetClientRect( PDC_hWnd, &client_rect);
2630
+ debug_printf( "Outgoing: %d %d\n", nlines, ncols);
2631
+ new_width = ncols * PDC_cxChar;
2632
+ new_height = nlines * PDC_cyChar;
2633
+
2634
+ if( new_width != client_rect.right || new_height != client_rect.bottom)
2635
+ { /* check to make sure size actually changed */
2636
+ add_resize_key = 0;
2637
+ SetWindowPos( PDC_hWnd, 0, 0, 0,
2638
+ new_width + (rect.right - rect.left) - client_rect.right,
2639
+ new_height + (rect.bottom - rect.top) - client_rect.bottom,
2640
+ SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
2641
+ }
2642
+ }
2643
+ return OK;
2644
+ }
2645
+
2646
+ void PDC_reset_prog_mode(void)
2647
+ {
2648
+ PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
2649
+ #ifdef NOT_CURRENTLY_IN_USE
2650
+ if( PDC_bDone == FALSE && PDC_hWnd)
2651
+ {
2652
+ PDC_bDone = TRUE;
2653
+ SetForegroundWindow( PDC_hWnd);
2654
+ }
2655
+ #endif
2656
+ }
2657
+
2658
+ void PDC_reset_shell_mode(void)
2659
+ {
2660
+ }
2661
+
2662
+ void PDC_restore_screen_mode(int i)
2663
+ {
2664
+ }
2665
+
2666
+ void PDC_save_screen_mode(int i)
2667
+ {
2668
+ }
2669
+
2670
+ /* NOTE: as with PDC_init_color() (see below), this function has to
2671
+ redraw all text with color attribute 'pair' to match the newly-set
2672
+ foreground and background colors. The loops to go through every character
2673
+ in curscr, looking for those that need to be redrawn and ignoring
2674
+ those at the front and start of each line, are very similar. */
2675
+
2676
+ static short get_pair( const chtype ch)
2677
+ {
2678
+ return( (short)( (ch & A_COLOR) >> PDC_COLOR_SHIFT));
2679
+ }
2680
+
2681
+ void PDC_init_pair( short pair, short fg, short bg)
2682
+ {
2683
+ if( color_pair_indices[pair] != fg ||
2684
+ color_pair_indices[pair + PDC_COLOR_PAIRS] != bg)
2685
+ {
2686
+ color_pair_indices[pair] = fg;
2687
+ color_pair_indices[pair + PDC_COLOR_PAIRS] = bg;
2688
+ /* Possibly go through curscr and redraw everything with that color! */
2689
+ if( curscr && curscr->_y)
2690
+ {
2691
+ int i;
2692
+
2693
+ for( i = 0; i < SP->lines; i++)
2694
+ if( curscr->_y[i])
2695
+ {
2696
+ int j = 0, n_chars;
2697
+ chtype *line = curscr->_y[i];
2698
+
2699
+ /* skip over starting text that isn't of the desired color: */
2700
+ while( j < SP->cols && get_pair( *line) != pair)
2701
+ {
2702
+ j++;
2703
+ line++;
2704
+ }
2705
+ n_chars = SP->cols - j;
2706
+ /* then skip over text at the end that's not the right color: */
2707
+ while( n_chars && get_pair( line[n_chars - 1]) != pair)
2708
+ n_chars--;
2709
+ if( n_chars)
2710
+ PDC_transform_line( i, j, n_chars, line);
2711
+ }
2712
+ }
2713
+ }
2714
+ }
2715
+
2716
+ int PDC_pair_content( short pair, short *fg, short *bg)
2717
+ {
2718
+ *fg = color_pair_indices[pair];
2719
+ *bg = color_pair_indices[pair + PDC_COLOR_PAIRS];
2720
+ return OK;
2721
+ }
2722
+
2723
+ bool PDC_can_change_color(void)
2724
+ {
2725
+ return TRUE;
2726
+ }
2727
+
2728
+ int PDC_color_content( short color, short *red, short *green, short *blue)
2729
+ {
2730
+ COLORREF col = pdc_rgbs[color];
2731
+
2732
+ *red = DIVROUND(GetRValue(col) * 1000, 255);
2733
+ *green = DIVROUND(GetGValue(col) * 1000, 255);
2734
+ *blue = DIVROUND(GetBValue(col) * 1000, 255);
2735
+
2736
+ return OK;
2737
+ }
2738
+
2739
+ /* We have an odd problem when changing colors with PDC_init_color(). On
2740
+ palette-based systems, you just change the palette and the hardware takes
2741
+ care of the rest. Here, though, we actually need to redraw any text that's
2742
+ drawn in the specified color. So we gotta look at each character and see if
2743
+ either the foreground or background matches the index that we're changing.
2744
+ Then, that text gets redrawn. For speed/simplicity, the code looks for the
2745
+ first and last character in each line that would be affected, then draws those
2746
+ in between (frequently, this will be zero characters, i.e., no text on that
2747
+ particular line happens to use the color index in question.) See similar code
2748
+ above for PDC_init_pair(), to handle basically the same problem. */
2749
+
2750
+ static int color_used_for_this_char( const chtype c, const int idx)
2751
+ {
2752
+ const int color = get_pair( c);
2753
+ const int rval = (color_pair_indices[color] == idx ||
2754
+ color_pair_indices[color + PDC_COLOR_PAIRS] == idx);
2755
+
2756
+ return( rval);
2757
+ }
2758
+
2759
+ int PDC_init_color( short color, short red, short green, short blue)
2760
+ {
2761
+ const COLORREF new_rgb = RGB(DIVROUND(red * 255, 1000),
2762
+ DIVROUND(green * 255, 1000),
2763
+ DIVROUND(blue * 255, 1000));
2764
+
2765
+ if( pdc_rgbs[color] != new_rgb)
2766
+ {
2767
+ pdc_rgbs[color] = new_rgb;
2768
+ /* Possibly go through curscr and redraw everything with that color! */
2769
+ if( curscr && curscr->_y)
2770
+ {
2771
+ int i;
2772
+
2773
+ for( i = 0; i < SP->lines; i++)
2774
+ if( curscr->_y[i])
2775
+ {
2776
+ int j = 0, n_chars;
2777
+ chtype *line = curscr->_y[i];
2778
+
2779
+ /* skip over starting text that isn't of the desired color: */
2780
+ while( j < SP->cols
2781
+ && !color_used_for_this_char( *line, color))
2782
+ {
2783
+ j++;
2784
+ line++;
2785
+ }
2786
+ n_chars = SP->cols - j;
2787
+ /* then skip over text at the end that's not the right color: */
2788
+ while( n_chars &&
2789
+ !color_used_for_this_char( line[n_chars - 1], color))
2790
+ n_chars--;
2791
+ if( n_chars)
2792
+ PDC_transform_line( i, j, n_chars, line);
2793
+ }
2794
+ }
2795
+ }
2796
+ return OK;
2797
+ }