ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/dclient/src/frontend/client/input_handler.cpp
Revision: 1.8
Committed: Sun Oct 24 20:31:52 2010 UTC (16 years ago) by sf-pippijn
Branch: MAIN
Changes since 1.7: +30 -29 lines
Log Message:
use EV and plain sockets instead of asio

File Contents

# Content
1 #include "deliantra/sender.h"
2
3 #include "dclient/input_handler.h"
4 #include "dclient/render_glyph.h"
5 #include "dclient/widgets.h"
6 #include "dclient/widgets/inventory.h"
7 #include "dclient/widgets/map.h"
8 #include "dclient/widgets/query.h"
9 #include "dclient/widgets/stats.h"
10
11 #include "adt/bind.h"
12
13 #include <ndk/application.hh>
14 #include <ndk/color.hh>
15
16 #include <curses.h>
17
18 #include <ev.h>
19
20 typedef unsigned long flags_t;
21
22 enum class flags
23 : flags_t
24 {
25 none,
26 firing = 1 << 0,
27 running = 1 << 1,
28
29 COUNT
30 };
31
32 static flags &
33 operator += (flags &lhs, flags rhs)
34 {
35 return lhs = flags (flags_t (lhs) | flags_t (rhs));
36 }
37
38 static flags &
39 operator -= (flags &lhs, flags rhs)
40 {
41 return lhs = flags (flags_t (lhs) & ~flags_t (rhs));
42 }
43
44 static bool
45 operator & (flags lhs, flags rhs)
46 {
47 return flags_t (lhs) & flags_t (rhs);
48 }
49
50
51 enum class action
52 {
53 none,
54
55 north,
56 northeast,
57 east,
58 southeast,
59 south,
60 southwest,
61 west,
62 northwest,
63
64 run,
65 fire,
66 stay_fire,
67
68 quit,
69 redraw,
70 resize,
71 maximise,
72 input_mode,
73
74 apply,
75 take,
76
77 COUNT
78 };
79
80
81 struct input_handler::pimpl
82 : sender
83 {
84 pimpl (communicator &comm, widgets &ui);
85
86 void perform (ndk::panel *sender, action cmd, action arg = action::none);
87
88 ndk::event::result on_kbd_common (ndk::keyboard const &ev);
89 ndk::event::result on_kbd_map (ndk::keyboard const &ev);
90
91 void on_command (std::string const &cmd);
92 void stdin_read_cb (ev::io &w, int revents);
93
94 widgets &ui;
95 std::string esc;
96 ev::io stdin_watcher;
97 flags state;
98 };
99
100 input_handler::pimpl::pimpl (communicator &comm, widgets &ui)
101 : sender (comm)
102 , ui (ui)
103 , state (flags::none)
104 {
105 auto kbd_common = ndk::slot (&pimpl::on_kbd_common, this);
106
107 ui.map->events ()->on_keyboard (kbd_common);
108 ui.info->events ()->on_keyboard (kbd_common);
109 ui.stats->events ()->on_keyboard (kbd_common);
110 ui.inventory->events ()->on_keyboard (kbd_common);
111 ui.container->events ()->on_keyboard (kbd_common);
112 ui.invmenu->events ()->on_keyboard (kbd_common);
113 ui.query->events ()->on_keyboard (kbd_common);
114
115 ui.map->events ()->on_keyboard (ndk::slot (&pimpl::on_kbd_map, this));
116
117 ui.input->on_commit () = ndk::slot (&pimpl::on_command, this);
118
119 stdin_watcher.set (STDIN_FILENO, ev::READ);
120 stdin_watcher.set<pimpl, &pimpl::stdin_read_cb> (this);
121 stdin_watcher.start ();
122 }
123
124 void
125 input_handler::pimpl::perform (ndk::panel *sender, action cmd, action arg)
126 {
127 struct ev_loop *loop = ev_default_loop ();
128
129 if (state & flags::running)
130 {
131 send ("command", "run_stop");
132 state -= flags::running;
133 }
134 if (state & flags::firing)
135 {
136 send ("command", "fire_stop");
137 state -= flags::firing;
138 }
139
140 switch (cmd)
141 {
142 case action::none:
143 break;
144
145 // direction commands
146 case action::north: send ("command", "north" ); break;
147 case action::northeast: send ("command", "northeast"); break;
148 case action::east: send ("command", "east" ); break;
149 case action::southeast: send ("command", "southeast"); break;
150 case action::south: send ("command", "south" ); break;
151 case action::southwest: send ("command", "southwest"); break;
152 case action::west: send ("command", "west" ); break;
153 case action::northwest: send ("command", "northwest"); break;
154
155 // running
156 case action::run:
157 send ("command", "run ", int (arg));
158 state += flags::running;
159 break;
160
161 // firing
162 case action::fire:
163 send ("command", "fire ", int (arg));
164 state += flags::firing;
165 break;
166
167 case action::stay_fire:
168 send ("command", "stay fire");
169 break;
170
171 // control commands
172 case action::quit:
173 ev_break (EV_A_ EVBREAK_ALL);
174 break;
175
176 case action::redraw:
177 redrawwin (stdscr);
178 break;
179
180 case action::resize:
181 ui.resize ();
182 break;
183
184 case action::maximise:
185 if (ui.maximised)
186 ui.maximised = nullptr;
187 else
188 ui.maximised = sender;
189 perform (sender, action::resize);
190 break;
191
192 case action::input_mode:
193 ui.input->visualize ();
194 ui.input->focus ();
195 break;
196
197 // action commands
198 case action::apply:
199 send ("command", "apply");
200 break;
201
202 case action::take:
203 send ("command", "take");
204 break;
205
206 // never happens
207 case action::COUNT:
208 abort ();
209 }
210 }
211
212 ndk::event::result
213 input_handler::pimpl::on_kbd_common (ndk::keyboard const &ev)
214 {
215 switch (ev.code ())
216 {
217 case ndk::key::error:
218 throw "ERR";
219
220 // control actions
221 case ndk::key::ctrl_d:
222 case 'q':
223 perform (ev.sender (), action::quit);
224 return ndk::event::accepted;
225
226 case ndk::key::ctrl_l:
227 perform (ev.sender (), action::redraw);
228 return ndk::event::accepted;
229
230 case ndk::key::resize:
231 perform (ev.sender (), action::resize);
232 return ndk::event::accepted;
233
234 case ndk::key::F10:
235 perform (ev.sender (), action::maximise);
236 return ndk::event::accepted;
237
238 default:
239 return ndk::event::ignored;
240 }
241 }
242
243 ndk::event::result
244 input_handler::pimpl::on_kbd_map (ndk::keyboard const &ev)
245 {
246 switch (ev.code ())
247 {
248 // moving
249 case 'j':
250 case '2':
251 case ndk::key::down:
252 perform (ev.sender (), action::south);
253 return ndk::event::accepted;
254 case 'k':
255 case '8':
256 case ndk::key::up:
257 perform (ev.sender (), action::north);
258 return ndk::event::accepted;
259 case 'h':
260 case '4':
261 case ndk::key::left:
262 perform (ev.sender (), action::west);
263 return ndk::event::accepted;
264 case 'l':
265 case '6':
266 case ndk::key::right:
267 perform (ev.sender (), action::east);
268 return ndk::event::accepted;
269 case '7':
270 case ndk::key::home:
271 perform (ev.sender (), action::northwest);
272 return ndk::event::accepted;
273 case '9':
274 case ndk::key::pg_up:
275 perform (ev.sender (), action::northeast);
276 return ndk::event::accepted;
277 case '5':
278 case ndk::key::numpad_center:
279 perform (ev.sender (), action::stay_fire);
280 return ndk::event::accepted;
281 case '1':
282 case ndk::key::end:
283 perform (ev.sender (), action::southwest);
284 return ndk::event::accepted;
285 case '3':
286 case ndk::key::pg_dn:
287 perform (ev.sender (), action::southeast);
288 return ndk::event::accepted;
289
290 case ' ':
291 perform (ev.sender (), action::apply);
292 return ndk::event::accepted;
293 case ',':
294 perform (ev.sender (), action::take);
295 return ndk::event::accepted;
296 case ndk::key::enter:
297 case 'i':
298 perform (ev.sender (), action::input_mode);
299 return ndk::event::accepted;
300 case 'c':
301 ui.input->set_text ("chat ");
302 perform (ev.sender (), action::input_mode);
303 return ndk::event::accepted;
304 case '"':
305 ui.input->set_text ("say ");
306 perform (ev.sender (), action::input_mode);
307 return ndk::event::accepted;
308 case '\'':
309 ui.input->set_text ("tell ");
310 perform (ev.sender (), action::input_mode);
311 return ndk::event::accepted;
312
313 // firing
314 case 'J':
315 case ndk::key::shift_down:
316 perform (ev.sender (), action::fire, action::south);
317 return ndk::event::accepted;
318 case 'K':
319 case ndk::key::shift_up:
320 perform (ev.sender (), action::fire, action::north);
321 return ndk::event::accepted;
322 case 'H':
323 case ndk::key::shift_left:
324 perform (ev.sender (), action::fire, action::west);
325 return ndk::event::accepted;
326 case 'L':
327 case ndk::key::shift_right:
328 perform (ev.sender (), action::fire, action::east);
329 return ndk::event::accepted;
330 case ndk::key::shift_home:
331 perform (ev.sender (), action::fire, action::northwest);
332 return ndk::event::accepted;
333 case ndk::key::shift_pg_up:
334 perform (ev.sender (), action::fire, action::northeast);
335 return ndk::event::accepted;
336 case ndk::key::shift_end:
337 perform (ev.sender (), action::fire, action::southwest);
338 return ndk::event::accepted;
339 case ndk::key::shift_pg_dn:
340 perform (ev.sender (), action::fire, action::southeast);
341 return ndk::event::accepted;
342
343 // running
344 //case 'J':
345 case ndk::key::ctrl_down:
346 perform (ev.sender (), action::run, action::south);
347 return ndk::event::accepted;
348 //case 'K':
349 case ndk::key::ctrl_up:
350 perform (ev.sender (), action::run, action::north);
351 return ndk::event::accepted;
352 //case 'H':
353 case ndk::key::ctrl_left:
354 perform (ev.sender (), action::run, action::west);
355 return ndk::event::accepted;
356 //case 'L':
357 case ndk::key::ctrl_right:
358 perform (ev.sender (), action::run, action::east);
359 return ndk::event::accepted;
360 case ndk::key::ctrl_home:
361 perform (ev.sender (), action::run, action::northwest);
362 return ndk::event::accepted;
363 case ndk::key::ctrl_pg_up:
364 perform (ev.sender (), action::run, action::northeast);
365 return ndk::event::accepted;
366 case ndk::key::ctrl_end:
367 perform (ev.sender (), action::run, action::southwest);
368 return ndk::event::accepted;
369 case ndk::key::ctrl_pg_dn:
370 perform (ev.sender (), action::run, action::southeast);
371 return ndk::event::accepted;
372
373 case ndk::key::ctrl_l:
374 case ndk::key::F10:
375 case ndk::key::resize:
376 case ndk::key::tab:
377 return ndk::event::ignored;
378
379 case ndk::key::unknown:
380 return ndk::event::ignored;
381
382 default:
383 if (getenv ("DCLIENT_FATAL"))
384 throw ev.code ();
385 else
386 {
387 ui.info->add_text (ndi_color (3, 0), "unknown keycode: 0%03o\n", ev.code ());
388 ui.info->visualize ();
389 return ndk::event::ignored;
390 }
391 }
392 }
393
394 void
395 input_handler::pimpl::on_command (std::string const &cmd)
396 {
397 ui.input->set_text ("");
398
399 if (!cmd.empty ())
400 send ("command", cmd);
401 else
402 {
403 ui.map->focus ();
404 ui.input->hide ();
405 ndk::app->cursor_off (); // FIXME: should be done automatically
406 }
407 }
408
409 void
410 input_handler::pimpl::stdin_read_cb (ev::io &w, int revents)
411 {
412 ndk::app->process (getch ());
413 }
414
415
416 input_handler::input_handler (communicator &comm, widgets &ui)
417 : impl (new pimpl (comm, ui))
418 {
419 }
420
421 input_handler::~input_handler ()
422 {
423 delete impl;
424 }