1 /* NetHack may be freely redistributed.  See license for details. */
2 
3 #include "winMS.h"
4 #include <assert.h>
5 #include "mhcmd.h"
6 #include "mhinput.h"
7 #include "mhcolor.h"
8 
9 static TCHAR szNHCmdWindowClass[] = TEXT("MSNethackCmdWndClass");
10 
11 #ifndef C
12 #  define C(c)		(0x1f & (c))
13 #endif
14 
15 /* cell status 0 */
16 #define NH_CST_CHECKED		1
17 
18 /* fonts */
19 #define NH_CMDPAD_FONT_NORMAL    0
20 #define NH_CMDPAD_FONT_MAX		 0
21 
22 /* type of the cell */
23 #define NH_CELL_REG			0
24 #define NH_CELL_CTRL		1
25 #define NH_CELL_CAP			2
26 #define NH_CELL_SHIFT		3
27 #define NH_CELL_LAYOUT_NEW	4
28 #define NH_CELL_LAYOUT_MENU	5
29 
30 #define NH_CMDSET_MAXSIZE	64
31 
32 /* Keypad cell information
33 
34 	NHCmdPadCell.cell_type    NHCmdPadCell.data
35 	-----------               ----------
36 	NH_CELL_REG				  (int)>=0 - index in the current keypad layout set (loads a new layout)
37 	                           -1      - restore default (saved) layout
38 	NH_CELL_CTRL			  not used
39 	NH_CELL_CAP				  not used
40 	NH_CELL_SHIFT			  not used
41 	NH_CELL_LAYOUT_NEW		  pointer to the new keypad layout layout (NHCmdLayout*)
42 	NH_CELL_LAYOUT_MENU       pointer to the layout set (NHCmdSet* - if NULL then nhcmdset_default is used)
43 */
44 typedef struct t_NHCmdPadCell {
45 	UINT		cmd_code;	/* Windows command code (menu processing - not implemented - set to -1) */
46 	char		f_char[16];	/* nethack char */
47 	char		text[16];	/* display text */
48 	int			image;		/* >0 - image ID in IDB_KEYPAD bitmap
49 	                           <=0 - absolute index of the font table */
50 	int			type;		/* cell type */
51 	int			mult;		/* cell width multiplier */
52 	void*		data;		/* internal data for the cell type */
53 } NHCmdPadCell, *PNHCmdPadCell;
54 
55 /* command layout */
56 typedef struct t_NHCmdLayout {
57 	char			name[64];
58 	int				rows;
59 	int				columns;
60 	NHCmdPadCell	cells[];
61 } NHCmdLayout, *PNHCmdLayout;
62 
63 /* set of command layouts */
64 typedef struct t_NHCmdSet {
65 	int count;
66 	struct t_NHCmdSetElem {
67 		PNHCmdLayout	layout;
68 		BOOL			free_on_destroy;
69 	} elements[NH_CMDSET_MAXSIZE];
70 } NHCmdSet, *PNHCmdSet;
71 
72 /* display cell layout */
73 typedef struct t_NHCmdPadLayoutCell {
74 	POINT   orig;		/* origin of the cell rect */
75 	BYTE	type;		/* cell type */
76 	int		state;		/* cell state */
77 } NHCmdPadLayoutCell, *PNHCmdPadLayoutCell;
78 
79 /* command window data */
80 typedef struct mswin_nethack_cmd_window {
81 	SIZE				cell_size;					/* cell size */
82 	HFONT				font[NH_CMDPAD_FONT_MAX+1];	/* fonts for cell text */
83 	HBITMAP				images;						/* key images map */
84 	int					active_cell;				/* current active cell */
85 
86 	boolean				is_caps;					/* is CAPS selected */
87 	boolean				is_ctrl;					/* is CRTL selected */
88 	boolean				is_shift;					/* is SHIFT selected */
89 
90 	PNHCmdLayout		layout_current;				/* current layout */
91 	PNHCmdLayout		layout_save;				/* saved layout */
92 	PNHCmdPadLayoutCell	cells;						/* display cells */
93 
94 #if defined(WIN_CE_SMARTPHONE)
95 	PNHCmdLayout		layout_selected;			/* since we use
96 													   layout command for menu also
97 	                                                   we need to store the layout
98 													   that was selected by a user
99 													 */
100 #endif
101 } NHCmdWindow, *PNHCmdWindow;
102 
103 
104 LRESULT CALLBACK NHCommandWndProc(HWND, UINT, WPARAM, LPARAM);
105 static void register_command_window_class();
106 static void LayoutCmdWindow(HWND hWnd);
107 static void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout);
108 static int CellFromPoint(PNHCmdWindow data, POINT pt );
109 static void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE windowSize);
110 static void HighlightCell(HWND hWnd, int cell, BOOL isSelected);
111 static void ActivateCell(HWND hWnd, int cell);
112 static void PushNethackCommand( const char* cmd_char_str, int is_ctrl );
113 
114 /*------------------- keyboard keys layout functions -----------------------*/
115 PNHCmdLayout	nhcmdlayout_create( const char* name, int rows, int columns );
116 void nhcmdlayout_init( PNHCmdLayout p, PNHCmdPadCell cells );
117 #define nhcmdlayout_rows(p)			((p)->rows)
118 #define nhcmdlayout_columns(p)		((p)->columns)
119 #define nhcmdlayout_row(p, x)		(&((p)->cells[(p)->columns*(x)]))
120 #define nhcmdlayout_cell(p, x, y)	(&((p)->cells[(p)->columns*(x)+(y)]))
121 #define nhcmdlayout_cell_direct(p, i)	(&((p)->cells[(i)]))
122 void			nhcmdlayout_destroy(PNHCmdLayout p);
123 
124 /*----------------- keyboard keys layout set functions ---------------------*/
125 PNHCmdSet		nhcmdset_create();
126 int				nhcmdset_count( PNHCmdSet p );
127 PNHCmdLayout	nhcmdset_get( PNHCmdSet p, int index );
128 const char*		nhcmdset_get_name( PNHCmdSet p, int index );
129 void			nhcmdset_add( PNHCmdSet p, PNHCmdLayout layout );
130 void			nhcmdset_destroy( PNHCmdSet p);
131 
132 /*-------------------- message handlers -----------------------------------*/
133 static void onPaint(HWND hWnd);				// on WM_PAINT
134 static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);	// on WM_CREATE
135 static void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam);	// on WM_LBUTTONDOWN
136 static void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam);	// on WM_MOUSEMOVE
137 static void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam);		// on WM_LBUTTONUP
138 
139 /*----------------------- static data -------------------------------------*/
140 static	PNHCmdSet nhcmdset_current = 0;
141 static	PNHCmdSet nhcmdset_default = 0;
142 
143 /*---------------------- Pre-definde keyboard layouts --------------------*/
144 #ifdef WIN_CE_SMARTPHONE
145 
146 /* dimensions of the command pad */
147 #define NH_CMDPAD_ROWS 4
148 #define NH_CMDPAD_COLS 3
149 #define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS*NH_CMDPAD_ROWS)
150 
151 /* layout indexes */
152 #define NH_LAYOUT_GENERAL		0
153 #define NH_LAYOUT_MOVEMENT		1
154 #define NH_LAYOUT_ATTACK		2
155 #define NH_LAYOUT_ITEM_HANDLING	3
156 #define NH_LAYOUT_CONTROLS		4
157 #define NH_LAYOUT_ADV_MOVEMENT	5
158 
159 /* template menu layout */
160 NHCmdPadCell cells_layout_menu[NH_CMDPAD_CELLNUM] =
161 {
162 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
163 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
164 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
165 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
166 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
167 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
168 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
169 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
170 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
171 	{ -1, "", "<<", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1 , NULL },
172 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 },
173 	{ -1, "", ">>", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1 , NULL }
174 };
175 
176 /* movement layout */
177 NHCmdPadCell cells_layout_movement[NH_CMDPAD_CELLNUM] =
178 {
179 	{ -1, "7", "7", 1, NH_CELL_REG, 1, (void*)-1 },
180 	{ -1, "8", "8", 2, NH_CELL_REG, 1, (void*)-1 },
181 	{ -1, "9", "9", 3, NH_CELL_REG, 1, (void*)-1 },
182 	{ -1, "4", "4", 4, NH_CELL_REG, 1, (void*)-1 },
183 	{ -1, ".", ".", 5, NH_CELL_REG, 1, (void*)-1 },
184 	{ -1, "6", "6", 6, NH_CELL_REG, 1, (void*)-1 },
185 	{ -1, "1", "1", 7, NH_CELL_REG, 1, (void*)-1 },
186 	{ -1, "2", "2", 8, NH_CELL_REG, 1, (void*)-1 },
187 	{ -1, "3", "3", 9, NH_CELL_REG, 1, (void*)-1 },
188 	{ -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 },
189 	{ -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 },
190 	{ -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 }
191 };
192 
193 /* attack layout */
194 NHCmdPadCell cells_layout_attack[NH_CMDPAD_CELLNUM] =
195 {
196 	{ -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
197 	{ -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
198 	{ -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
199 	{ -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
200 	{ -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
201 	{ -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
202 	{ -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
203 	{ -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
204 	{ -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
205 	{ -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
206 	{ -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
207 	{ -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
208 };
209 
210 /* item handling layout */
211 NHCmdPadCell cells_layout_item_handling[NH_CMDPAD_CELLNUM] =
212 {
213 	{ -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
214 	{ -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
215 	{ -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
216 	{ -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
217 	{ -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
218 	{ -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
219 	{ -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
220 	{ -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
221 	{ -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
222 	{ -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
223 	{ -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
224 	{ -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
225 };
226 
227 /* General */
228 NHCmdPadCell cells_layout_general[NH_CMDPAD_CELLNUM] =
229 {
230 	{ -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
231 	{ -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
232 	{ -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
233 	{ -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
234 	{ -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
235 	{ -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
236 	{ -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
237 	{ -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
238 	{ -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
239 	{ -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
240 	{ -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
241 	{ -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
242 };
243 
244 /* game controls layout */
245 NHCmdPadCell cells_layout_game[NH_CMDPAD_CELLNUM] =
246 {
247 	{ -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
248 	{ -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
249 	{ -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
250 	{ -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
251 	{ -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
252 	{ -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
253 	{ -1, "&", "&", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
254 	{ -1, "\x18", "^X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
255 	{ -1, "\x10", "^P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
256 	{ -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
257 	{ -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
258 	{ -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
259 };
260 
261 /* advanced movement layout */
262 NHCmdPadCell cells_layout_adv_movement[NH_CMDPAD_CELLNUM] =
263 {
264 	{ -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
265 	{ -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
266 	{ -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
267 	{ -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT },
268 	{ -1, "_", "_", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
269 	{ -1, "\x14", "^T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
270 	{ -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
271 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
272 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
273 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
274 	{ -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
275 	{ -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 }
276 };
277 
278 #else /* !WIN_CE_SMARTPHONE */
279 
280 /* dimensions of the command pad */
281 #define NH_CMDPAD_ROWS 4
282 #define NH_CMDPAD_COLS 14
283 #define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS*NH_CMDPAD_ROWS)
284 
285 /* lowercase layout */
286 NHCmdPadCell cells_layout_mod1[NH_CMDPAD_ROWS*NH_CMDPAD_COLS] =
287 {
288 	{ -1, "7", "7", 1, NH_CELL_REG, 1, (void*)-1 },
289 	{ -1, "8", "8", 2, NH_CELL_REG, 1, (void*)-1 },
290 	{ -1, "9", "9", 3, NH_CELL_REG, 1, (void*)-1 },
291 	{ -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2 , NULL },
292 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for ESC */
293 	{ -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
294 	{ -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
295 	{ -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
296 	{ -1, "/", "/", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
297 	{ -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
298 	{ -1, ";", ";", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
299 	{ -1, "-", "-", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
300 	{ -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
301 	{ -1, "^", "^", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
302 
303 	{ -1, "4", "4", 4, NH_CELL_REG, 1, (void*)-1 },
304 	{ -1, "5", "5", 5, NH_CELL_REG, 1, (void*)-1 },
305 	{ -1, "6", "6", 6, NH_CELL_REG, 1, (void*)-1 },
306 	{ -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2 , NULL },
307 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CAPS */
308 	{ -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
309 	{ -1, "b", "b", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
310 	{ -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
311 	{ -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
312 	{ -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
313 	{ -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
314 	{ -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
315 	{ -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
316 	{ -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
317 
318 	{ -1, "1", "1", 7, NH_CELL_REG, 1, (void*)-1 },
319 	{ -1, "2", "2", 8, NH_CELL_REG, 1, (void*)-1 },
320 	{ -1, "3", "3", 9, NH_CELL_REG, 1, (void*)-1 },
321 	{ -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2 , NULL },
322 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for shift */
323 	{ -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
324 	{ -1, "k", "k", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
325 	{ -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
326 	{ -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
327 	{ -1, "n", "n", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
328 	{ -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
329 	{ -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
330 	{ -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
331 	{ -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
332 
333 	{ -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 },
334 	{ -1, ".", ".", 11, NH_CELL_REG, 1, (void*)-1 },
335 	{ -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 },
336 	{ -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2 , NULL },
337 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CTRL */
338 	{ -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
339 	{ -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
340 	{ -1, "u", "u", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
341 	{ -1, "v", "v", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
342 	{ -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
343 	{ -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
344 	{ -1, "y", "y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
345 	{ -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
346 	{ -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }
347 };
348 
349 /* uppercase layout */
350 NHCmdPadCell cells_layout_mod2[-NH_CMDPAD_ROWS*-NH_CMDPAD_COLS] =
351 {
352 	{ -1, "7", "7", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
353 	{ -1, "8", "8", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
354 	{ -1, "9", "9", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
355 	{ -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2 , NULL },
356 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for ESC */
357 	{ -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
358 	{ -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
359 	{ -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
360 	{ -1, "(", "(", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
361 	{ -1, ")", ")", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
362 	{ -1, "+", "+", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
363 	{ -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
364 	{ -1, "\"", "\"", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
365 	{ -1, "$", "$", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
366 
367 	{ -1, "4", "4", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
368 	{ -1, "5", "5", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
369 	{ -1, "6", "6", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
370 	{ -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2 , NULL },
371 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CAPS */
372 	{ -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
373 	{ -1, "B", "B", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
374 	{ -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
375 	{ -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
376 	{ -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
377 	{ -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
378 	{ -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
379 	{ -1, "H", "H", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
380 	{ -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
381 
382 	{ -1, "1", "1", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
383 	{ -1, "2", "2", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
384 	{ -1, "3", "3", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
385 	{ -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2 , NULL },
386 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for shift */
387 	{ -1, "J", "J", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
388 	{ -1, "K", "K", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
389 	{ -1, "L", "L", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
390 	{ -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
391 	{ -1, "N", "N", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
392 	{ -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
393 	{ -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
394 	{ -1, "Q", "Q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
395 	{ -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
396 
397 	{ -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 },
398 	{ -1, "0", "0", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
399 	{ -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 },
400 	{ -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2 , NULL },
401 		{ -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CTRL */
402 	{ -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
403 	{ -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
404 	{ -1, "U", "U", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
405 	{ -1, "V", "V", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
406 	{ -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
407 	{ -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
408 	{ -1, "Y", "Y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
409 	{ -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 },
410 	{ -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }
411 };
412 
413 #endif /* !WIN_CE_SMARTPHONE */
414 
415 /*-------------------------------------------------------------------------*/
mswin_init_command_window()416 HWND mswin_init_command_window () {
417 	static int run_once = 0;
418 	HWND ret;
419 
420 	/* register window class */
421 	if( !run_once ) {
422 		register_command_window_class();
423 		run_once = 1;
424 	}
425 
426 	/* create window */
427 	ret = CreateWindow(
428 			szNHCmdWindowClass,		/* registered class name */
429 			NULL,					/* window name */
430 			WS_CHILD | WS_CLIPSIBLINGS, /* window style */
431 			0,  /* horizontal position of window - set it later */
432 			0,  /* vertical position of window - set it later */
433 			0,  /* window width - set it later */
434 			0,  /* window height - set it later*/
435 			GetNHApp()->hMainWnd,	/* handle to parent or owner window */
436 			NULL,					/* menu handle or child identifier */
437 			GetNHApp()->hApp,		/* handle to application instance */
438 			NULL );					/* window-creation data */
439 	if( !ret ) {
440 		panic("Cannot create command window");
441 	}
442 	return ret;
443 }
444 /*-------------------------------------------------------------------------*/
445 /* calculate mimimum window size */
mswin_command_window_size(HWND hwnd,LPSIZE sz)446 void mswin_command_window_size (HWND hwnd, LPSIZE sz)
447 {
448 	SIZE cell_size;
449 	PNHCmdWindow data;
450 	data = (PNHCmdWindow)GetWindowLong(hwnd, GWL_USERDATA);
451 	if( !data ) {
452 		sz->cx = sz->cy = 0;
453 	} else {
454 		CalculateCellSize(hwnd, &cell_size, sz);
455 		sz->cx = max(
456 					cell_size.cx*nhcmdlayout_columns(data->layout_current)+2*GetSystemMetrics(SM_CXBORDER),
457 					sz->cx
458 					);
459 		sz->cy = max(
460 					cell_size.cy*nhcmdlayout_rows(data->layout_current)+2*GetSystemMetrics(SM_CYBORDER),
461 					sz->cy
462 					);
463 	}
464 }
465 /*-------------------------------------------------------------------------*/
register_command_window_class()466 void register_command_window_class()
467 {
468 	WNDCLASS wcex;
469 	PNHCmdLayout plt;
470 	ZeroMemory( &wcex, sizeof(wcex));
471 
472 	/* window class */
473 	wcex.style			= CS_NOCLOSE;
474 	wcex.lpfnWndProc	= (WNDPROC)NHCommandWndProc;
475 	wcex.cbClsExtra		= 0;
476 	wcex.cbWndExtra		= 0;
477 	wcex.hInstance		= GetNHApp()->hApp;
478 	wcex.hIcon			= NULL;
479 	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
480 	wcex.hbrBackground	= mswin_get_brush(NHW_KEYPAD, MSWIN_COLOR_BG);
481 	wcex.lpszMenuName	= NULL;
482 	wcex.lpszClassName	= szNHCmdWindowClass;
483 
484 	if( !RegisterClass(&wcex) ) {
485 		panic("cannot register Map window class");
486 	}
487 
488 	/* create default command set */
489 	nhcmdset_current = nhcmdset_default = nhcmdset_create();
490 
491 #ifdef WIN_CE_SMARTPHONE
492 	plt = nhcmdlayout_create("General", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
493 	nhcmdlayout_init(plt, cells_layout_general);
494 	nhcmdset_add(nhcmdset_current, plt);
495 
496 	plt = nhcmdlayout_create("Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
497 	nhcmdlayout_init(plt, cells_layout_movement);
498 	nhcmdset_add(nhcmdset_current, plt );
499 
500 	plt = nhcmdlayout_create("Attack", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
501 	nhcmdlayout_init(plt, cells_layout_attack);
502 	nhcmdset_add(nhcmdset_current, plt);
503 
504 	plt = nhcmdlayout_create("Item Handling", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
505 	nhcmdlayout_init(plt, cells_layout_item_handling);
506 	nhcmdset_add(nhcmdset_current, plt);
507 
508 	plt = nhcmdlayout_create("Game Controls", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
509 	nhcmdlayout_init(plt, cells_layout_game);
510 	nhcmdset_add(nhcmdset_current, plt);
511 
512 	plt = nhcmdlayout_create("Advanced Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
513 	nhcmdlayout_init(plt, cells_layout_adv_movement);
514 	nhcmdset_add(nhcmdset_current, plt);
515 #else /* ! WIN_CE_SMARTPHONE */
516 	plt = nhcmdlayout_create("lowercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
517 	nhcmdlayout_init(plt, cells_layout_mod1);
518 	nhcmdset_add(nhcmdset_current, plt);
519 
520 	plt = nhcmdlayout_create("uppercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
521 	nhcmdlayout_init(plt, cells_layout_mod2);
522 	nhcmdset_add(nhcmdset_current, plt);
523 #endif /* WIN_CE_SMARTPHONE */
524 }
525 /*-------------------------------------------------------------------------*/
NHCommandWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)526 LRESULT CALLBACK NHCommandWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
527 {
528 	PNHCmdWindow data;
529 	int i;
530 
531 	switch (message)
532 	{
533 	case WM_CREATE:
534 		onCreate( hWnd, wParam, lParam );
535 		break;
536 
537 	case WM_PAINT:
538 		onPaint(hWnd);
539 		break;
540 
541     case WM_SIZE:
542 		LayoutCmdWindow(hWnd);
543 		break;
544 
545 	case WM_LBUTTONDOWN:
546 		onMouseDown(hWnd, wParam, lParam);
547 		return 0;
548 
549 	case WM_MOUSEMOVE:
550 		/* proceed only if if have mouse focus (set in onMouseDown() -
551 		   left mouse button is pressed) */
552 		if( GetCapture()==hWnd ) {
553 			onMouseMove(hWnd, wParam, lParam);
554 			return 0;
555 		} else {
556 			return 1;
557 		}
558 		break;
559 
560 	case WM_LBUTTONUP:
561 		/* proceed only if if have mouse focus (set in onMouseDown()) */
562 		if( GetCapture()==hWnd ) {
563 			onMouseUp(hWnd, wParam, lParam);
564 			return 0;
565 		} else {
566 			return 1;
567 		}
568 		break;
569 
570 	case WM_DESTROY:
571 		data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
572 		for(i=0; i<=NH_CMDPAD_FONT_MAX; i++ )
573 			if( data->font[i] ) DeleteObject(data->font[i]);
574 		free(data);
575 		SetWindowLong(hWnd, GWL_USERDATA, (LONG)0);
576 		break;
577 
578 	default:
579 		return DefWindowProc(hWnd, message, wParam, lParam);
580 	}
581 	return FALSE;
582 }
583 /*-------------------------------------------------------------------------*/
onPaint(HWND hWnd)584 void onPaint(HWND hWnd)
585 {
586 	PNHCmdWindow data;
587 	PAINTSTRUCT ps;
588 	HDC hDC;
589 	int x, y;
590 	TCHAR wbuf[BUFSZ];
591 	HGDIOBJ saveFont;
592 	BITMAP	bm;
593 	int  cell_index;
594 
595 	/* get window data */
596 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
597 
598 	hDC = BeginPaint(hWnd, &ps);
599 
600 	if( !IsRectEmpty(&ps.rcPaint) ) {
601 		HGDIOBJ oldBr;
602 		HBRUSH hbrPattern;
603 		COLORREF OldBg, OldFg;
604 		HPEN hPen;
605 		HGDIOBJ hOldPen;
606 
607 		saveFont = SelectObject(hDC, data->font[NH_CMDPAD_FONT_NORMAL]);
608 		OldBg = SetBkColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_BG));
609 		OldFg = SetTextColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG));
610 
611 		GetObject(data->images, sizeof(BITMAP), (LPVOID)&bm);
612 
613 		hbrPattern = CreatePatternBrush(data->images);
614 		hPen = CreatePen(PS_SOLID, 1, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG));
615 
616 		for( x=0, cell_index = 0; x<nhcmdlayout_rows(data->layout_current); x++ )
617 		for( y=0; y<nhcmdlayout_columns(data->layout_current); y++, cell_index++ ) {
618 			RECT cell_rt;
619 			POINT pt[5];
620 			PNHCmdPadCell p_cell_data;
621 
622 			p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell_index);
623 
624 			/* calculate the cell rectangle */
625 			cell_rt.left = data->cells[cell_index].orig.x;
626 			cell_rt.top = data->cells[cell_index].orig.y;
627 			cell_rt.right = data->cells[cell_index].orig.x + data->cell_size.cx*p_cell_data->mult;
628 			cell_rt.bottom = data->cells[cell_index].orig.y + data->cell_size.cy;
629 
630 			/* draw border */
631 			hOldPen = SelectObject(hDC, hPen);
632 			pt[0].x = cell_rt.left;
633 			pt[0].y = cell_rt.top;
634 			pt[1].x = cell_rt.right;
635 			pt[1].y = cell_rt.top;
636 			pt[2].x = cell_rt.right;
637 			pt[2].y = cell_rt.bottom;
638 			pt[3].x = cell_rt.left;
639 			pt[3].y = cell_rt.bottom;
640 			pt[4].x = cell_rt.left;
641 			pt[4].y = cell_rt.top;
642 			Polyline(hDC, pt, 5);
643 			SelectObject(hDC, hOldPen);
644 
645 			/* calculate clipping rectangle for the text */
646 			cell_rt.left++;
647 			cell_rt.top ++;
648 			cell_rt.right--;
649 			cell_rt.bottom--;
650 
651 			/* draw the cell text */
652 			if( p_cell_data->image<=0 ) {
653 				SelectObject(hDC, data->font[ -p_cell_data->image ]);
654 				DrawText(hDC,
655 						NH_A2W(p_cell_data->text, wbuf, BUFSZ),
656 						strlen(p_cell_data->text),
657 						&cell_rt,
658 						DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX
659 						);
660 			} else {
661 				/* draw bitmap */
662 				int bmOffset;
663 				RECT bitmap_rt;
664 
665 				bmOffset = (p_cell_data->image - 1)*bm.bmHeight;
666 
667 				bitmap_rt.left = ((cell_rt.left+cell_rt.right) - min(bm.bmHeight, (cell_rt.right-cell_rt.left)))/2;
668 				bitmap_rt.top = ((cell_rt.bottom+cell_rt.top) - min(bm.bmHeight, (cell_rt.bottom-cell_rt.top)))/2;
669 				bitmap_rt.right = bitmap_rt.left + min(bm.bmHeight, (cell_rt.right-cell_rt.left));
670 				bitmap_rt.bottom = bitmap_rt.top + min(bm.bmHeight, (cell_rt.bottom-cell_rt.top));
671 
672 				SetBrushOrgEx(hDC, bitmap_rt.left-bmOffset, bitmap_rt.top, NULL);
673 				oldBr = SelectObject(hDC, hbrPattern);
674 				PatBlt(
675 					hDC,
676 					bitmap_rt.left,
677 					bitmap_rt.top,
678 					bitmap_rt.right-bitmap_rt.left,
679 					bitmap_rt.bottom-bitmap_rt.top,
680 					PATCOPY);
681 				SelectObject(hDC, oldBr);
682 			}
683 
684 			/* invert the cell if it is selected */
685 			if( data->cells[cell_index].state == NH_CST_CHECKED ) {
686 				IntersectRect( &cell_rt, &cell_rt, &ps.rcPaint);
687 				PatBlt( hDC,
688 						cell_rt.left,
689 						cell_rt.top,
690 						cell_rt.right - cell_rt.left,
691 						cell_rt.bottom - cell_rt.top,
692 						DSTINVERT
693 						);
694 			}
695 		}
696 
697 		SetTextColor(hDC, OldFg);
698 		SetBkColor(hDC, OldBg);
699 		SelectObject(hDC, saveFont);
700 		DeleteObject(hbrPattern);
701 		DeleteObject(hPen);
702 	}
703 	EndPaint(hWnd, &ps);
704 }
705 /*-------------------------------------------------------------------------*/
onCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)706 void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
707 {
708 	PNHCmdWindow data;
709 
710 	/* set window data */
711 	data = (PNHCmdWindow)malloc(sizeof(NHCmdWindow));
712 	if( !data ) panic("out of memory");
713 
714 	ZeroMemory(data, sizeof(NHCmdWindow));
715 	SetWindowLong(hWnd, GWL_USERDATA, (LONG)data);
716 
717 	data->active_cell = -1;
718 
719 	/* load images bitmap */
720 	data->images = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_KEYPAD));
721 	if( !data->images ) panic("cannot load keypad bitmap");
722 
723 	/* create default layouts */
724 	data->layout_current = 0;
725 	data->layout_save = 0;
726 	data->cells = 0;
727 
728 #if defined(WIN_CE_SMARTPHONE)
729 	data->layout_selected = nhcmdset_get(nhcmdset_current, 0);
730 #endif
731 
732 	/* set default layout */
733 	SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, 0));
734 }
735 /*-------------------------------------------------------------------------*/
LayoutCmdWindow(HWND hWnd)736 void LayoutCmdWindow(HWND hWnd)
737 {
738 	RECT clrt;
739 	SIZE windowSize;
740 	PNHCmdWindow data;
741 	int i, j;
742 	int x, y;
743 	LOGFONT lgfnt;
744 	int index;
745 
746 	GetClientRect(hWnd, &clrt);
747 	if( IsRectEmpty(&clrt) ) return;
748 
749 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
750 	if( !data->layout_current ) return;
751 
752 	/* calculate cell size */
753 	windowSize.cx = clrt.right-clrt.left;
754 	windowSize.cy = clrt.bottom-clrt.top;
755 	CalculateCellSize(hWnd, &data->cell_size, &windowSize);
756 
757 	/* initialize display cells aray */
758 	x = 0;
759 	y = 0;
760 	for( i=0, index=0; i<nhcmdlayout_rows(data->layout_current); i++ ) {
761 		for( j=0; j<nhcmdlayout_columns(data->layout_current); j++, index++ ) {
762 			data->cells[index].orig.x = x;
763 			data->cells[index].orig.y = y;
764 			data->cells[index].type = nhcmdlayout_cell_direct(data->layout_current, index)->type;
765 
766 			switch(data->cells[index].type) {
767 			case NH_CELL_CTRL:
768 				data->cells[index].state = data->is_ctrl? NH_CST_CHECKED : 0;
769 				break;
770 			case NH_CELL_CAP:
771 				data->cells[index].state = data->is_caps? NH_CST_CHECKED : 0;
772 				break;
773 			case NH_CELL_SHIFT:
774 				data->cells[index].state = data->is_shift? NH_CST_CHECKED : 0;
775 				break;
776 			default:
777 				data->cells[index].state = 0;
778 			}
779 
780 			x += data->cell_size.cx * nhcmdlayout_cell_direct(data->layout_current, index)->mult;
781 		}
782 		x = 0;
783 		y += data->cell_size.cy;
784 	}
785 
786 	/* create font for display cell text */
787 	for(i=0; i<=NH_CMDPAD_FONT_MAX; i++ )
788 		if( data->font[i] ) DeleteObject(data->font[i]);
789 
790 	ZeroMemory( &lgfnt, sizeof(lgfnt) );
791 	lgfnt.lfHeight			=	data->cell_size.cy; // height of font
792 	lgfnt.lfWidth			=	0; // average character width
793 	lgfnt.lfEscapement		=	0;					 // angle of escapement
794 	lgfnt.lfOrientation		=	0;					 // base-line orientation angle
795 	lgfnt.lfWeight			=	FW_NORMAL;			// font weight
796 	lgfnt.lfItalic			=	FALSE;			     // italic attribute option
797 	lgfnt.lfUnderline		=	FALSE;				// underline attribute option
798 	lgfnt.lfStrikeOut		=	FALSE;				// strikeout attribute option
799 	lgfnt.lfCharSet			=	ANSI_CHARSET;     // character set identifier
800 	lgfnt.lfOutPrecision	=	OUT_DEFAULT_PRECIS;  // output precision
801 	lgfnt.lfClipPrecision	=	CLIP_CHARACTER_PRECIS; // clipping precision
802 	lgfnt.lfQuality			=	DEFAULT_QUALITY;     // output quality
803 	if( iflags.wc_font_message &&
804 		*iflags.wc_font_message ) {
805 		lgfnt.lfPitchAndFamily	= DEFAULT_PITCH;		 // pitch and family
806 		NH_A2W( iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE);
807 	} else {
808 		lgfnt.lfPitchAndFamily	= VARIABLE_PITCH;		 // pitch and family
809 	}
810 	data->font[NH_CMDPAD_FONT_NORMAL] = CreateFontIndirect(&lgfnt);
811 
812 	InvalidateRect(hWnd, NULL, TRUE);
813 }
814 /*-------------------------------------------------------------------------*/
SetCmdWindowLayout(HWND hWnd,PNHCmdLayout layout)815 void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout)
816 {
817 	PNHCmdWindow data;
818 	int size;
819 
820 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
821 	if( data->layout_current == layout ) return;
822 
823 	data->layout_current = layout;
824 	size = sizeof(NHCmdPadLayoutCell)*nhcmdlayout_rows(layout)*nhcmdlayout_columns(layout);
825 	data->cells = (PNHCmdPadLayoutCell)realloc(data->cells, size);
826 	ZeroMemory(data->cells, size);
827 	LayoutCmdWindow(hWnd);
828 }
829 /*-------------------------------------------------------------------------*/
onMouseDown(HWND hWnd,WPARAM wParam,LPARAM lParam)830 void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
831 {
832 	PNHCmdWindow data;
833 	POINT mpt;
834 
835 	/* get mouse coordinates */
836 	mpt.x = LOWORD(lParam);
837 	mpt.y = HIWORD(lParam);
838 
839 	/* map mouse coordinates to the display cell */
840 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
841 	data->active_cell = CellFromPoint(data, mpt);
842 	if( data->active_cell==-1 ) return;
843 
844 	/* set mouse focus to the current window */
845 	SetCapture(hWnd);
846 
847 	/* invert the selection */
848 	HighlightCell(hWnd, data->active_cell, (data->cells[data->active_cell].state!=NH_CST_CHECKED) );
849 }
850 /*-------------------------------------------------------------------------*/
onMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam)851 void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
852 {
853 	PNHCmdWindow data;
854 	POINT mpt;
855 	int newActiveCell;
856 
857 	/* get mouse coordinates */
858 	mpt.x = LOWORD(lParam);
859 	mpt.y = HIWORD(lParam);
860 
861 	/* map mouse coordinates to the display cell */
862 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
863 	newActiveCell = CellFromPoint(data, mpt);
864 	if( data->active_cell == -1 ) return;
865 
866 	/* if mouse is within orginal display cell - select the cell otherwise
867 	   clear the selection */
868 	switch( nhcmdlayout_cell_direct(data->layout_current, data->active_cell)->type ) {
869 	case NH_CELL_REG:
870 		HighlightCell(hWnd, data->active_cell,
871 			       (newActiveCell==data->active_cell) );
872 		break;
873 
874 	case NH_CELL_CTRL:
875 		HighlightCell(hWnd, data->active_cell,
876 			((newActiveCell==data->active_cell)? !data->is_ctrl : data->is_ctrl) );
877 		break;
878 
879 	case NH_CELL_CAP:
880 		HighlightCell(hWnd, data->active_cell,
881 			((newActiveCell==data->active_cell)? !data->is_caps : data->is_caps) );
882 		break;
883 	}
884 }
885 /*-------------------------------------------------------------------------*/
onMouseUp(HWND hWnd,WPARAM wParam,LPARAM lParam)886 void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
887 {
888 	PNHCmdWindow data;
889 
890 	/* release mouse capture */
891 	ReleaseCapture();
892 
893 	/* get active display cell */
894 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
895 	if( data->active_cell == -1 ) return;
896 
897 	ActivateCell(hWnd, data->active_cell);
898 
899 	data->active_cell = -1;
900 }
901 /*-------------------------------------------------------------------------*/
ActivateCell(HWND hWnd,int cell)902 void ActivateCell(HWND hWnd, int cell)
903 {
904 	PNHCmdWindow data;
905 	PNHCmdPadCell p_cell_data;
906 	int i;
907 
908 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
909 	if( !data ) return;
910 	p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell);
911 
912 	/* act depending on the cell type:
913 		CAPS - change layout
914 		CTRL - modify CTRL status
915 		REG  - place keyboard event on the nethack input queue
916 	*/
917 	switch( p_cell_data->type ) {
918 	case NH_CELL_REG:
919 		if( data->is_ctrl ) {
920 			PushNethackCommand(p_cell_data->f_char, 1);
921 
922 			data->is_ctrl = 0;
923 			for( i=0; i<nhcmdlayout_rows(data->layout_current)*nhcmdlayout_columns(data->layout_current); i++ ) {
924 				if( nhcmdlayout_cell_direct(data->layout_current, i)->type == NH_CELL_CTRL ) {
925 					HighlightCell(hWnd, i, data->is_ctrl);
926 				}
927 			}
928 		} else {
929 			PushNethackCommand(p_cell_data->f_char, 0);
930 		}
931 		HighlightCell(hWnd, cell, FALSE);
932 
933 		// select a new layout if present
934 		i = (int)p_cell_data->data;
935 		if( i==-1 ) {
936 			if( data->layout_save ) SetCmdWindowLayout(hWnd, data->layout_save);
937 			data->layout_save = NULL;
938 		} else {
939 			if( !data->layout_save ) data->layout_save = data->layout_current;
940 			SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, i));
941 		}
942 
943 		if( !data->is_shift ) break;
944 		// else fall through and reset the shift
945 
946 	case NH_CELL_SHIFT:
947 		data->is_shift = !data->is_shift;
948 		SetCmdWindowLayout(
949 			hWnd,
950 			(data->is_shift ^ data->is_caps)? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0)
951 		);
952 		data->cells[cell].state = data->is_shift? NH_CST_CHECKED : 0;
953 		InvalidateRect(hWnd, NULL, TRUE);
954 		break;
955 
956 	case NH_CELL_CTRL:
957 		data->is_ctrl = !data->is_ctrl;
958 		HighlightCell(hWnd, cell, data->is_ctrl);
959 		break;
960 
961 	case NH_CELL_CAP:
962 		data->is_caps = !data->is_caps;
963 		SetCmdWindowLayout(
964 			hWnd,
965 			(data->is_shift ^ data->is_caps)? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0)
966 		);
967 		data->cells[cell].state = data->is_caps? NH_CST_CHECKED : 0;
968 		InvalidateRect(hWnd, NULL, TRUE);
969 		break;
970 
971 	case NH_CELL_LAYOUT_NEW: {
972 		PNHCmdLayout pLayout;
973 
974 		HighlightCell(hWnd, cell, FALSE);
975 
976 		pLayout = (PNHCmdLayout)p_cell_data->data;
977 		if( pLayout ) {
978 			SetCmdWindowLayout(hWnd, pLayout);
979 		}
980 	} break;
981 
982 	case NH_CELL_LAYOUT_MENU: {
983 		winid wid;
984 		int i;
985 		anything any;
986 		menu_item* selected = 0;
987 		PNHCmdSet pSet;
988 
989 		HighlightCell(hWnd, cell, FALSE);
990 
991 		pSet = (PNHCmdSet)p_cell_data->data;
992 		if( !pSet ) pSet = nhcmdset_default;
993 
994 		wid = mswin_create_nhwindow(NHW_MENU);
995 		mswin_start_menu(wid);
996 		for( i=0; i<nhcmdset_count(pSet); i++ ) {
997 			any.a_void = nhcmdset_get(pSet, i);
998 			mswin_add_menu(wid, NO_GLYPH, &any, 'a'+i, 0, ATR_NONE,
999 				nhcmdset_get_name(pSet, i), FALSE);
1000 		}
1001 		mswin_end_menu(wid, "Select keypad layout");
1002 	    i = select_menu(wid, PICK_ONE, &selected);
1003 	    mswin_destroy_nhwindow(wid);
1004 
1005 		if( i==1 ) {
1006 #if defined(WIN_CE_SMARTPHONE)
1007 			data->layout_selected = (PNHCmdLayout)selected[0].item.a_void;
1008 #endif
1009 			SetCmdWindowLayout(hWnd, (PNHCmdLayout)selected[0].item.a_void );
1010 		}
1011 	} break;
1012 
1013 	}
1014 }
1015 /*-------------------------------------------------------------------------*/
CellFromPoint(PNHCmdWindow data,POINT pt)1016 int CellFromPoint(PNHCmdWindow data, POINT pt )
1017 {
1018 	int i;
1019 	for( i=0; i<nhcmdlayout_rows(data->layout_current)*nhcmdlayout_columns(data->layout_current); i++ ) {
1020 		RECT cell_rt;
1021 		cell_rt.left = data->cells[i].orig.x;
1022 		cell_rt.top = data->cells[i].orig.y;
1023 		cell_rt.right = data->cells[i].orig.x + data->cell_size.cx*nhcmdlayout_cell_direct(data->layout_current, i)->mult;
1024 		cell_rt.bottom = data->cells[i].orig.y + data->cell_size.cy;
1025 		if( PtInRect(&cell_rt, pt) ) return i;
1026 	}
1027 	return -1;
1028 }
1029 /*-------------------------------------------------------------------------*/
CalculateCellSize(HWND hWnd,LPSIZE pSize,LPSIZE pWindowSize)1030 void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE pWindowSize)
1031 {
1032 	HDC hdc;
1033 	PNHCmdWindow data;
1034 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
1035 	if( !data ) return;
1036 
1037 	hdc = GetDC(hWnd);
1038 
1039 	/* if windows size is specified - attempt ro stretch cells across
1040 	   the the window size. If not - make default cell size based on
1041 	   10 points font. Make sure that cell cesize does not exceeds 20 points */
1042 	if( pWindowSize->cx>0 )
1043 		pSize->cx = pWindowSize->cx/nhcmdlayout_columns(data->layout_current);
1044 	else
1045 		pSize->cx = 10*GetDeviceCaps(hdc, LOGPIXELSX)/72;
1046 	pSize->cx = min(pSize->cx, 20*GetDeviceCaps(hdc, LOGPIXELSX)/72 );
1047 
1048 	if( pWindowSize->cy>0 )
1049 		pSize->cy = pWindowSize->cy/nhcmdlayout_rows(data->layout_current);
1050 	else
1051 		pSize->cy = 10*GetDeviceCaps(hdc, LOGPIXELSY)/72;
1052 	pSize->cy = min(pSize->cy, 20*GetDeviceCaps(hdc, LOGPIXELSY)/72 );
1053 
1054 	ReleaseDC(hWnd, hdc);
1055 }
1056 /*-------------------------------------------------------------------------*/
HighlightCell(HWND hWnd,int cell,BOOL isSelected)1057 void HighlightCell(HWND hWnd, int cell, BOOL isSelected)
1058 {
1059 	HDC hDC;
1060 	PNHCmdWindow data;
1061 	int prevState;
1062 
1063 	data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA);
1064 	prevState = data->cells[cell].state;
1065 	data->cells[cell].state = (isSelected)? NH_CST_CHECKED : 0;
1066 
1067 	if( prevState!=data->cells[cell].state ) {
1068 		hDC = GetDC(hWnd);
1069 		PatBlt( hDC,
1070 			data->cells[cell].orig.x+1,
1071 			data->cells[cell].orig.y+1,
1072 			data->cell_size.cx*nhcmdlayout_cell_direct(data->layout_current, cell)->mult - 2,
1073 			data->cell_size.cy - 2,
1074 			DSTINVERT
1075 			);
1076 		ReleaseDC(hWnd, hDC);
1077 	}
1078 }
1079 /*-------------------------------------------------------------------------*/
PushNethackCommand(const char * cmd_char_str,int is_ctrl)1080 void PushNethackCommand( const char* cmd_char_str, int is_ctrl )
1081 {
1082 	while( *cmd_char_str ) {
1083 		if( is_ctrl ) { NHEVENT_KBD( C(*cmd_char_str) ); }
1084 		else		  { NHEVENT_KBD( *cmd_char_str ); }
1085 		cmd_char_str++;
1086 	}
1087 }
1088 
1089 /*-------------------------------------------------------------------------*/
1090 /*------------------- keyboard keys layout functions ----------------------*/
1091 /*-------------------------------------------------------------------------*/
nhcmdlayout_create(const char * name,int rows,int columns)1092 PNHCmdLayout nhcmdlayout_create(const char* name, int rows, int columns)
1093 {
1094 	PNHCmdLayout p;
1095 	int i;
1096 
1097 	i = sizeof(NHCmdLayout)+rows*columns*sizeof(NHCmdPadCell);
1098 	p = (PNHCmdLayout)malloc(i);
1099 	ZeroMemory(p, i);
1100 	p->rows = rows;
1101 	p->columns = columns;
1102 	strncpy(p->name, name, sizeof(p->name)-1);
1103 	for(i=0; i<rows*columns; i++) {
1104 		p->cells[i].cmd_code = -1;
1105 		p->cells[i].image = -NH_CMDPAD_FONT_NORMAL;
1106 		p->cells[i].type = 1;
1107 		p->cells[i].mult = 1;
1108 	}
1109 	return p;
1110 }
1111 /*-------------------------------------------------------------------------*/
nhcmdlayout_init(PNHCmdLayout p,PNHCmdPadCell cells)1112 void nhcmdlayout_init( PNHCmdLayout p, PNHCmdPadCell cells )
1113 {
1114 	memcpy(p->cells, cells, p->rows*p->columns*sizeof(NHCmdPadCell));
1115 }
1116 
nhcmdlayout_destroy(PNHCmdLayout p)1117 void nhcmdlayout_destroy(PNHCmdLayout p)
1118 {
1119 	free(p);
1120 }
1121 
1122 /*-------------------------------------------------------------------------*/
1123 /*----------------- keyboard keys layout set functions --------------------*/
1124 /*-------------------------------------------------------------------------*/
nhcmdset_create()1125 PNHCmdSet nhcmdset_create()
1126 {
1127 	PNHCmdSet p;
1128 	p = (PNHCmdSet)malloc(sizeof(NHCmdSet));
1129 	ZeroMemory(p, sizeof(NHCmdSet));
1130 	return p;
1131 }
1132 /*-------------------------------------------------------------------------*/
nhcmdset_count(PNHCmdSet p)1133 int nhcmdset_count(PNHCmdSet p)
1134 {
1135 	assert(p);
1136 	return p->count;
1137 }
1138 /*-------------------------------------------------------------------------*/
nhcmdset_get(PNHCmdSet p,int index)1139 PNHCmdLayout nhcmdset_get( PNHCmdSet p, int index )
1140 {
1141 	assert(p);
1142 	assert(index>=0 && index<p->count);
1143 	return p->elements[index].layout;
1144 }
1145 /*-------------------------------------------------------------------------*/
nhcmdset_get_name(PNHCmdSet p,int index)1146 const char*	nhcmdset_get_name( PNHCmdSet p, int index )
1147 {
1148 	assert(p);
1149 	assert(index>=0 && index<p->count);
1150 	return p->elements[index].layout->name;
1151 }
1152 /*-------------------------------------------------------------------------*/
nhcmdset_add(PNHCmdSet p,PNHCmdLayout layout)1153 void nhcmdset_add( PNHCmdSet p, PNHCmdLayout layout )
1154 {
1155 	assert(p);
1156 	assert(p->count<NH_CMDSET_MAXSIZE);
1157 	p->elements[p->count].layout = layout;
1158 	p->elements[p->count].free_on_destroy = 0;
1159 	p->count++;
1160 }
1161 /*-------------------------------------------------------------------------*/
nhcmdset_destroy(PNHCmdSet p)1162 void nhcmdset_destroy(PNHCmdSet p)
1163 {
1164 	int i=0;
1165 	assert(p);
1166 	for(i=0; i<p->count; i++) {
1167 		if( p->elements[i].free_on_destroy ) {
1168 			nhcmdlayout_destroy( p->elements[i].layout );
1169 		}
1170 	}
1171 	free(p);
1172 }
1173 /*-------------------------------------------------------------------------*/
1174 
1175 
1176 #if defined(WIN_CE_SMARTPHONE)
1177 /* special keypad input handling for SmartPhone
1178    the phone keypad maps to VK_* as shown below.
1179    some keys might not be present, e.g. VK_TFLIP
1180     sofkey1     softkey2    VK_TSOFT1, VK_TSOFT2
1181             ^               VK_TUP
1182         <   +   >           VK_TLEFT, VK_TACTION, VK_TRIGHT
1183             v               VK_TDOWN
1184     home        back        VK_THOME, VK_TBACK
1185     talk        end         VK_TTALK, VK_TEND
1186     1       2       3       VK_T0..VK_T9
1187     4       5       6       ...
1188     7       8       9       ...
1189     *       0       #       VK_TSTAR, VK_TPOUND
1190    other buttons include
1191     VK_TRECORD
1192     VK_TPOWER, VK_TVOLUMEUP, VK_TVOLUMEDOWN
1193     VK_TFLIP
1194 */
NHSPhoneTranslateKbdMessage(WPARAM wParam,LPARAM lParam,BOOL keyDown)1195 BOOL NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown)
1196 {
1197 	PNHCmdWindow data;
1198 	int index = -1;
1199 
1200 	/* get window data */
1201 	data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
1202 	if( !data ) return FALSE;
1203 
1204 	switch (wParam) {
1205     case VK_T0:
1206 		index = 10;
1207 	break;
1208 
1209     case VK_T1:
1210 		index = 0;
1211 	break;
1212 
1213     case VK_T2:
1214 		index = 1;
1215 	break;
1216 
1217     case VK_T3:
1218 		index = 2;
1219 	break;
1220 
1221     case VK_T4:
1222 		index = 3;
1223 	break;
1224 
1225     case VK_T5:
1226 		index = 4;
1227 	break;
1228 
1229     case VK_T6:
1230 		index = 5;
1231 	break;
1232 
1233     case VK_T7:
1234 		index = 6;
1235 	break;
1236 
1237     case VK_T8:
1238 		index = 7;
1239 	break;
1240 
1241     case VK_T9:
1242 		index = 8;
1243 	break;
1244 
1245 	case VK_TSTAR:
1246 		index = 9;
1247 	break;
1248 
1249 	case VK_TPOUND:
1250 		index = 11;
1251 	break;
1252 	}
1253 
1254 	if( index>=0 ) {
1255 		HighlightCell(GetNHApp()->hCmdWnd, index, keyDown);
1256 		if( keyDown ) ActivateCell(GetNHApp()->hCmdWnd, index);
1257 		return TRUE;
1258 	} else {
1259 		return FALSE;
1260 	}
1261 }
1262 /*-------------------------------------------------------------------------*/
NHSPhoneSetKeypadFromString(const char * str)1263 void NHSPhoneSetKeypadFromString(const char* str)
1264 {
1265 	PNHCmdWindow data;
1266 	PNHCmdSet p = 0;
1267 	PNHCmdLayout layout_prev = 0;
1268 	PNHCmdLayout layout_cur = 0;
1269 	char buf[2][BUFSZ];
1270 	int i, lcount;
1271 	char *s;
1272 
1273 	assert(NH_CMDPAD_ROWS==4);
1274 
1275 	data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
1276 	if( !data ) return;
1277 
1278 	p = nhcmdset_create();
1279 
1280 	ZeroMemory(buf, sizeof(buf));
1281 	if( sscanf(str, "%s or %s", buf[1], buf[0])!=2 ) {
1282 		ZeroMemory(buf, sizeof(buf));
1283 		strncpy(buf[0], str, sizeof(buf[0])-1);
1284 	}
1285 
1286 	lcount = 10; /* create new layout on the first iteration */
1287 	for(i=0; i<2; i++) {
1288 		s = buf[i];
1289 		while( *s ) {
1290 			char c_start, c_end, c_char;
1291 
1292 			/* parse character ranges */
1293 			if( isalnum( (c_start=s[0]) ) &&
1294 				s[1]=='-' &&
1295 				isalnum( (c_end=s[2]) ) ) {
1296 				s += 2;
1297 			} else {
1298 				c_start = c_end = *s;
1299 			}
1300 
1301 			for( c_char=c_start; c_char<=c_end; c_char++ ) {
1302 				if( lcount>=10 ) {
1303 					/* create layout */
1304 					lcount = 0;
1305 					layout_prev = layout_cur;
1306 					layout_cur = nhcmdlayout_create("noname", NH_CMDPAD_ROWS, NH_CMDPAD_COLS);
1307 					nhcmdlayout_init(layout_cur, cells_layout_menu);
1308 
1309 					nhcmdlayout_cell(layout_cur, 3, 0)->data = layout_prev;
1310 					nhcmdlayout_cell(layout_cur, 3, 2)->data = 0;
1311 
1312 					nhcmdset_add( p, layout_cur );
1313 					p->elements[p->count-1].free_on_destroy = 1;
1314 
1315 					if( layout_prev ) {
1316 						nhcmdlayout_cell(layout_prev, 3, 2)->data = layout_cur;
1317 					}
1318 				}
1319 
1320 				if( lcount==9 ) lcount=10; // skip '#'
1321 				nhcmdlayout_cell_direct(layout_cur, lcount)->f_char[0] = c_char;
1322 				if( c_char == '\033' ) {
1323 					strcpy(nhcmdlayout_cell_direct(layout_cur, lcount)->text, "esc");
1324 					nhcmdlayout_cell_direct(layout_cur, lcount)->image = 14; /* 14 is a ESC symbol in IDB_KEYPAD */
1325 				} else {
1326 					nhcmdlayout_cell_direct(layout_cur, lcount)->text[0] = c_char;
1327 					nhcmdlayout_cell_direct(layout_cur, lcount)->text[1] = '\x0';
1328 				}
1329 
1330 				/* increment character count in the current layout */
1331 				lcount++;
1332 			}
1333 
1334 			/* prepareg next charcter from the source string */
1335 			s++;
1336 		}
1337 	}
1338 
1339 	/* install the new set */
1340 	if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current );
1341 	nhcmdset_current = p;
1342 	SetCmdWindowLayout(
1343 			GetNHApp()->hCmdWnd,
1344 			nhcmdset_get(nhcmdset_current, 0)
1345 	);
1346 }
1347 /*-------------------------------------------------------------------------*/
NHSPhoneSetKeypadDirection()1348 void NHSPhoneSetKeypadDirection()
1349 {
1350 	PNHCmdWindow data;
1351 
1352 	data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
1353 	if( !data ) return;
1354 
1355 	if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current );
1356 	nhcmdset_current = nhcmdset_default;
1357 	SetCmdWindowLayout(
1358 		GetNHApp()->hCmdWnd,
1359 		nhcmdset_get(nhcmdset_current, NH_LAYOUT_MOVEMENT)
1360 	);
1361 }
1362 /*-------------------------------------------------------------------------*/
NHSPhoneSetKeypadDefault()1363 void NHSPhoneSetKeypadDefault()
1364 {
1365 	PNHCmdWindow data;
1366 
1367 	data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA);
1368 	if( !data ) return;
1369 
1370 	if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current );
1371 	nhcmdset_current = nhcmdset_default;
1372 	SetCmdWindowLayout(
1373 		GetNHApp()->hCmdWnd,
1374 		data->layout_selected ? data->layout_selected : nhcmdset_get(nhcmdset_current, 0)
1375 	);
1376 }
1377 
1378 #endif /* defined (WIN_CE_SMARTHPONE) */
1379