1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software{} you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation{} either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY{} without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program{} if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/glk_api.h"
24 #include "glk/conf.h"
25 #include "glk/events.h"
26 #include "glk/picture.h"
27 #include "glk/sound.h"
28 #include "glk/streams.h"
29 #include "glk/unicode.h"
30 #include "glk/windows.h"
31 #include "glk/window_graphics.h"
32 #include "glk/window_text_buffer.h"
33 #include "glk/window_pair.h"
34 #include "common/translation.h"
35
36 namespace Glk {
37
GlkAPI(OSystem * syst,const GlkGameDescription & gameDesc)38 GlkAPI::GlkAPI(OSystem *syst, const GlkGameDescription &gameDesc) :
39 GlkEngine(syst, gameDesc), _gliFirstEvent(false) {
40 // Set uppercase/lowercase tables
41 int ix, res;
42 for (ix = 0; ix < 256; ix++) {
43 _charToupperTable[ix] = ix;
44 _charTolowerTable[ix] = ix;
45 }
46
47 for (ix = 0; ix < 256; ix++) {
48 if (ix >= 'A' && ix <= 'Z')
49 res = ix + ('a' - 'A');
50 else if (ix >= 0xC0 && ix <= 0xDE && ix != 0xD7)
51 res = ix + 0x20;
52 else
53 res = 0;
54
55 if (res) {
56 _charTolowerTable[ix] = res;
57 _charToupperTable[res] = ix;
58 }
59 }
60 }
61
glk_exit(void)62 void GlkAPI::glk_exit(void) {
63 glk_put_string(_("[ press any key to exit ]"));
64 _events->waitForPress();
65
66 // Trigger a ScumMVM shutdown of game
67 quitGame();
68 Common::Event e;
69 g_system->getEventManager()->pollEvent(e);
70 }
71
glk_set_interrupt_handler(void (* func)(void))72 void GlkAPI::glk_set_interrupt_handler(void(*func)(void)) {
73 // This library doesn't handle interrupts.
74 }
75
glk_tick(void)76 void GlkAPI::glk_tick(void) {
77 // Nothing needed
78 }
79
glk_gestalt(uint id,uint val)80 uint GlkAPI::glk_gestalt(uint id, uint val) {
81 return glk_gestalt_ext(id, val, nullptr, 0);
82 }
83
glk_gestalt_ext(uint id,uint val,uint * arr,uint arrlen)84 uint GlkAPI::glk_gestalt_ext(uint id, uint val, uint *arr, uint arrlen) {
85 switch (id) {
86 case gestalt_Version:
87 return 0x00000703;
88
89 case gestalt_LineInput:
90 if (val >= 32 && val < 0x10ffff)
91 return true;
92 else
93 return false;
94
95 case gestalt_CharInput:
96 if (val >= 32 && val < 0x10ffff)
97 return true;
98 else if (val == keycode_Return)
99 return true;
100 else
101 return false;
102
103 case gestalt_CharOutput:
104 if (val >= 32 && val < 0x10ffff) {
105 if (arr && arrlen >= 1)
106 arr[0] = 1;
107 return gestalt_CharOutput_ExactPrint;
108 } else {
109 // cheaply, we don't do any translation of printed characters,
110 // so the output is always one character even if it's wrong.
111 if (arr && arrlen >= 1)
112 arr[0] = 1;
113 return gestalt_CharOutput_CannotPrint;
114 }
115
116 case gestalt_MouseInput:
117 if (val == wintype_TextGrid)
118 return true;
119 if (val == wintype_Graphics)
120 return true;
121 return false;
122
123 case gestalt_Graphics:
124 case gestalt_GraphicsTransparency:
125 return g_conf->_graphics;
126
127 case gestalt_DrawImage:
128 if (val == wintype_TextBuffer)
129 return g_conf->_graphics;
130 if (val == wintype_Graphics)
131 return g_conf->_graphics;
132 return false;
133
134 case gestalt_Sound:
135 case gestalt_SoundVolume:
136 case gestalt_SoundMusic:
137 case gestalt_SoundNotify:
138 return g_conf->_sound;
139
140 case gestalt_LineTerminatorKey:
141 return Window::checkBasicTerminators(val);
142
143 case gestalt_Timer:
144 case gestalt_Unicode:
145 case gestalt_UnicodeNorm:
146 case gestalt_Hyperlinks:
147 case gestalt_HyperlinkInput:
148 case gestalt_LineInputEcho:
149 case gestalt_LineTerminators:
150 case gestalt_DateTime:
151 case gestalt_GarglkText:
152 return true;
153
154 case gestalt_Sound2:
155 default:
156 return false;
157 }
158 }
159
glk_char_to_lower(unsigned char ch)160 unsigned char GlkAPI::glk_char_to_lower(unsigned char ch) {
161 return _charTolowerTable[ch];
162 }
163
glk_char_to_upper(unsigned char ch)164 unsigned char GlkAPI::glk_char_to_upper(unsigned char ch) {
165 return _charToupperTable[ch];
166 }
167
glk_window_get_root(void) const168 winid_t GlkAPI::glk_window_get_root(void) const {
169 return _windows->getRoot();
170 }
171
glk_window_open(winid_t split,uint method,uint size,uint wintype,uint rock) const172 winid_t GlkAPI::glk_window_open(winid_t split, uint method, uint size, uint wintype, uint rock) const {
173 return _windows->windowOpen(split, method, size, wintype, rock);
174 }
175
glk_window_close(winid_t win,stream_result_t * result)176 void GlkAPI::glk_window_close(winid_t win, stream_result_t *result) {
177 if (win) {
178 _windows->windowClose(win, result);
179 } else {
180 warning("glk_window_close: invalid ref");
181 }
182 }
183
glk_window_get_size(winid_t win,uint * width,uint * height)184 void GlkAPI::glk_window_get_size(winid_t win, uint *width, uint *height) {
185 if (win) {
186 win->getSize(width, height);
187 } else {
188 warning("window_get_size: invalid ref");
189 }
190 }
191
glk_window_set_arrangement(winid_t win,uint method,uint size,winid_t keywin)192 void GlkAPI::glk_window_set_arrangement(winid_t win, uint method, uint size, winid_t keywin) {
193 if (win) {
194 win->setArrangement(method, size, keywin);
195 } else {
196 warning("window_set_arrangement: invalid ref");
197 }
198 }
199
glk_window_get_arrangement(winid_t win,uint * method,uint * size,winid_t * keyWin)200 void GlkAPI::glk_window_get_arrangement(winid_t win, uint *method,
201 uint *size, winid_t *keyWin) {
202 if (win) {
203 win->getArrangement(method, size, keyWin);
204 } else {
205 warning("window_get_arrangement: invalid ref");
206 }
207 }
208
glk_window_iterate(winid_t win,uint * rock)209 winid_t GlkAPI::glk_window_iterate(winid_t win, uint *rock) {
210 win = win ? win->_next : _windows->getRoot();
211
212 if (win) {
213 if (rock)
214 *rock = win->_rock;
215 return win;
216 }
217
218 if (rock)
219 *rock = 0;
220
221 return nullptr;
222 }
223
glk_window_get_rock(winid_t win)224 uint GlkAPI::glk_window_get_rock(winid_t win) {
225 if (win) {
226 return win->_rock;
227 } else {
228 warning("window_get_rock: invalid ref.");
229 return 0;
230 }
231 }
232
glk_window_get_type(winid_t win)233 uint GlkAPI::glk_window_get_type(winid_t win) {
234 if (win) {
235 return win->_type;
236 } else {
237 warning("window_get_parent: invalid ref");
238 return 0;
239 }
240 }
241
glk_window_get_parent(winid_t win)242 winid_t GlkAPI::glk_window_get_parent(winid_t win) {
243 if (!win) {
244 warning("window_get_parent: invalid ref");
245 return 0;
246 }
247
248 return win->_parent;
249 }
250
glk_window_get_sibling(winid_t win)251 winid_t GlkAPI::glk_window_get_sibling(winid_t win) {
252 if (!win) {
253 warning("window_get_sibling: invalid ref");
254 return nullptr;
255 }
256
257 PairWindow *parentWin = dynamic_cast<PairWindow *>(win->_parent);
258 if (!parentWin)
259 return nullptr;
260
261 int index = parentWin->_children.indexOf(win);
262 if (index == ((int)parentWin->_children.size() - 1))
263 return parentWin->_children.front();
264 else if (index >= 0)
265 return parentWin->_children[index + 1];
266
267 return nullptr;
268 }
269
glk_window_clear(winid_t win)270 void GlkAPI::glk_window_clear(winid_t win) {
271 if (!win) {
272 warning("window_clear: invalid ref");
273 } else {
274 if (win->_lineRequest || win->_lineRequestUni) {
275 if (g_conf->_safeClicks && _events->_forceClick) {
276 glk_cancel_line_event(win, nullptr);
277 _events->_forceClick = false;
278
279 win->clear();
280 } else {
281 warning("window_clear: window has pending line request");
282 return;
283 }
284 }
285
286 // Clear the window
287 win->clear();
288 }
289 }
290
glk_window_move_cursor(winid_t win,uint xpos,uint ypos)291 void GlkAPI::glk_window_move_cursor(winid_t win, uint xpos, uint ypos) {
292 if (win) {
293 win->moveCursor(Point(xpos, ypos));
294 } else {
295 warning("window_move_cursor: invalid ref");
296 }
297 }
298
glk_window_get_stream(winid_t win)299 strid_t GlkAPI::glk_window_get_stream(winid_t win) {
300 if (win) {
301 return win->_stream;
302 } else {
303 warning("window_get_stream: invalid ref");
304 return nullptr;
305 }
306 }
307
glk_window_set_echo_stream(winid_t win,strid_t str)308 void GlkAPI::glk_window_set_echo_stream(winid_t win, strid_t str) {
309 if (win) {
310 win->_echoStream = str;
311 } else {
312 warning("window_set_echo_stream: invalid window id");
313 }
314 }
315
glk_window_get_echo_stream(winid_t win)316 strid_t GlkAPI::glk_window_get_echo_stream(winid_t win) {
317 if (!win) {
318 warning("window_get_echo_stream: invalid ref");
319 return nullptr;
320 }
321
322 return win->_echoStream;
323 }
324
glk_set_window(winid_t win)325 void GlkAPI::glk_set_window(winid_t win) {
326 _streams->setCurrent(win ? win->_stream : nullptr);
327 }
328
glk_stream_open_file(frefid_t fileref,FileMode fmode,uint rock)329 strid_t GlkAPI::glk_stream_open_file(frefid_t fileref, FileMode fmode, uint rock) {
330 return _streams->openFileStream(fileref, fmode, rock, false);
331 }
332
glk_stream_open_memory(char * buf,uint buflen,FileMode fmode,uint rock)333 strid_t GlkAPI::glk_stream_open_memory(char *buf, uint buflen, FileMode fmode, uint rock) {
334 return _streams->openMemoryStream(buf, buflen, fmode, rock, false);
335 }
336
glk_stream_close(strid_t str,stream_result_t * result)337 void GlkAPI::glk_stream_close(strid_t str, stream_result_t *result) {
338 str->close(result);
339 }
340
glk_stream_iterate(strid_t str,uint * rockptr) const341 strid_t GlkAPI::glk_stream_iterate(strid_t str, uint *rockptr) const {
342 return str ? str->getNext(rockptr) : _streams->getFirst(rockptr);
343 }
344
glk_stream_get_rock(strid_t str) const345 uint GlkAPI::glk_stream_get_rock(strid_t str) const {
346 if (!str) {
347 warning("stream_get_rock: invalid ref");
348 return 0;
349 }
350
351 return str->getRock();
352 }
353
glk_stream_set_position(strid_t str,int pos,uint seekMode)354 void GlkAPI::glk_stream_set_position(strid_t str, int pos, uint seekMode) {
355 if (str) {
356 str->setPosition(pos, seekMode);
357 } else {
358 warning("stream_set_position: invalid ref");
359 }
360 }
361
glk_stream_get_position(strid_t str) const362 uint GlkAPI::glk_stream_get_position(strid_t str) const {
363 if (str) {
364 return str->getPosition();
365 } else {
366 warning("stream_get_position: invalid ref");
367 return 0;
368 }
369 }
370
glk_stream_set_current(strid_t str)371 void GlkAPI::glk_stream_set_current(strid_t str) {
372 _streams->setCurrent(str);
373 }
374
glk_stream_get_current(void)375 strid_t GlkAPI::glk_stream_get_current(void) {
376 return _streams->getCurrent();
377 }
378
glk_put_char(unsigned char ch)379 void GlkAPI::glk_put_char(unsigned char ch) {
380 _streams->getCurrent()->putChar(ch);
381 }
382
glk_put_char_stream(strid_t str,unsigned char ch)383 void GlkAPI::glk_put_char_stream(strid_t str, unsigned char ch) {
384 if (str) {
385 str->putChar(ch);
386 } else {
387 warning("put_char_stream: invalid ref");
388 }
389 }
390
glk_put_string(const char * s)391 void GlkAPI::glk_put_string(const char *s) {
392 _streams->getCurrent()->putBuffer(s, strlen(s));
393 }
394
glk_put_string_stream(strid_t str,const char * s)395 void GlkAPI::glk_put_string_stream(strid_t str, const char *s) {
396 str->putBuffer(s, strlen(s));
397 }
398
glk_put_buffer(const char * buf,uint len)399 void GlkAPI::glk_put_buffer(const char *buf, uint len) {
400 _streams->getCurrent()->putBuffer(buf, len);
401 }
402
glk_put_buffer_stream(strid_t str,const char * buf,uint len)403 void GlkAPI::glk_put_buffer_stream(strid_t str, const char *buf, uint len) {
404 str->putBuffer(buf, len);
405 }
406
glk_set_style(uint styl)407 void GlkAPI::glk_set_style(uint styl) {
408 _streams->getCurrent()->setStyle(styl);
409 }
410
glk_set_style_stream(strid_t str,uint styl)411 void GlkAPI::glk_set_style_stream(strid_t str, uint styl) {
412 if (str) {
413 str->setStyle(styl);
414 } else {
415 warning("set_style_stream: invalid ref");
416 }
417 }
418
glk_get_char_stream(strid_t str)419 int GlkAPI::glk_get_char_stream(strid_t str) {
420 if (str) {
421 return str->getChar();
422 } else {
423 warning("get_char_stream: invalid ref");
424 return -1;
425 }
426 }
427
glk_get_line_stream(strid_t str,char * buf,uint len)428 uint GlkAPI::glk_get_line_stream(strid_t str, char *buf, uint len) {
429 if (str) {
430 return str->getLine(buf, len);
431 } else {
432 warning("get_line_stream: invalid ref");
433 return 0;
434 }
435 }
436
glk_get_buffer_stream(strid_t str,char * buf,uint len)437 uint GlkAPI::glk_get_buffer_stream(strid_t str, char *buf, uint len) {
438 if (str) {
439 return str->getBuffer(buf, len);
440 } else {
441 warning("get_line_stream: invalid ref");
442 return 0;
443 }
444 }
445
glk_stylehint_set(uint wintype,uint style,uint hint,int val)446 void GlkAPI::glk_stylehint_set(uint wintype, uint style, uint hint, int val) {
447 WindowStyle *styles;
448 bool p, b, i;
449
450 if (wintype == wintype_AllTypes) {
451 glk_stylehint_set(wintype_TextGrid, style, hint, val);
452 glk_stylehint_set(wintype_TextBuffer, style, hint, val);
453 return;
454 }
455
456 if (wintype == wintype_TextGrid)
457 styles = g_conf->_gStyles;
458 else if (wintype == wintype_TextBuffer)
459 styles = g_conf->_tStyles;
460 else
461 return;
462
463 if (!g_conf->_styleHint)
464 return;
465
466 switch (hint) {
467 case stylehint_TextColor:
468 styles[style].fg = val;
469 break;
470
471 case stylehint_BackColor:
472 styles[style].bg = val;
473 break;
474
475 case stylehint_ReverseColor:
476 styles[style].reverse = (val != 0);
477 break;
478
479 case stylehint_Proportional:
480 if (wintype == wintype_TextBuffer) {
481 p = val > 0;
482 b = styles[style].isBold();
483 i = styles[style].isItalic();
484 styles[style].font = WindowStyle::makeFont(p, b, i);
485 }
486 break;
487
488 case stylehint_Weight:
489 p = styles[style].isProp();
490 b = val > 0;
491 i = styles[style].isItalic();
492 styles[style].font = WindowStyle::makeFont(p, b, i);
493 break;
494
495 case stylehint_Oblique:
496 p = styles[style].isProp();
497 b = styles[style].isBold();
498 i = val > 0;
499 styles[style].font = WindowStyle::makeFont(p, b, i);
500 break;
501 }
502
503 if (wintype == wintype_TextBuffer && style == style_Normal && hint == stylehint_BackColor) {
504 g_conf->_windowColor = styles[style].bg;
505 }
506
507 if (wintype == wintype_TextBuffer && style == style_Normal && hint == stylehint_TextColor) {
508 g_conf->_propInfo._moreColor = styles[style].fg;
509 g_conf->_propInfo._caretColor = styles[style].fg;
510 }
511 }
512
glk_stylehint_clear(uint wintype,uint style,uint hint)513 void GlkAPI::glk_stylehint_clear(uint wintype, uint style, uint hint) {
514 WindowStyle *styles;
515 const WindowStyle *defaults;
516
517 if (wintype == wintype_AllTypes) {
518 glk_stylehint_clear(wintype_TextGrid, style, hint);
519 glk_stylehint_clear(wintype_TextBuffer, style, hint);
520 return;
521 }
522
523 if (wintype == wintype_TextGrid) {
524 styles = g_conf->_gStyles;
525 defaults = g_conf->_gStylesDefault;
526 } else if (wintype == wintype_TextBuffer) {
527 styles = g_conf->_tStyles;
528 defaults = g_conf->_tStylesDefault;
529 } else {
530 return;
531 }
532
533 if (!g_conf->_styleHint)
534 return;
535
536 switch (hint) {
537 case stylehint_TextColor:
538 styles[style].fg = defaults[style].fg;
539 break;
540
541 case stylehint_BackColor:
542 styles[style].bg = defaults[style].bg;
543 break;
544
545 case stylehint_ReverseColor:
546 styles[style].reverse = defaults[style].reverse;
547 break;
548
549 case stylehint_Proportional:
550 case stylehint_Weight:
551 case stylehint_Oblique:
552 styles[style].font = defaults[style].font;
553 break;
554 }
555 }
556
glk_style_distinguish(winid_t win,uint style1,uint style2)557 uint GlkAPI::glk_style_distinguish(winid_t win, uint style1, uint style2) {
558 const WindowStyle *styles = win->getStyles();
559 if (!styles)
560 return false;
561
562 return styles[style1] == styles[style2] ? 0 : 1;
563 }
564
glk_style_measure(winid_t win,uint style,uint hint,uint * result)565 bool GlkAPI::glk_style_measure(winid_t win, uint style, uint hint, uint *result) {
566 const WindowStyle *styles = win->getStyles();
567 if (!styles)
568 return false;
569
570 switch (hint) {
571 case stylehint_Indentation:
572 case stylehint_ParaIndentation:
573 *result = 0;
574 break;
575
576 case stylehint_Justification:
577 *result = stylehint_just_LeftFlush;
578 break;
579
580 case stylehint_Size:
581 *result = 1;
582 break;
583
584 case stylehint_Weight:
585 *result =
586 (styles[style].font == PROPB || styles[style].font == PROPZ ||
587 styles[style].font == MONOB || styles[style].font == MONOZ);
588 break;
589
590 case stylehint_Oblique:
591 *result =
592 (styles[style].font == PROPI || styles[style].font == PROPZ ||
593 styles[style].font == MONOI || styles[style].font == MONOZ);
594 break;
595
596 case stylehint_Proportional:
597 *result =
598 (styles[style].font == PROPR || styles[style].font == PROPI ||
599 styles[style].font == PROPB || styles[style].font == PROPZ);
600 break;
601
602 case stylehint_TextColor:
603 *result = styles[style].fg;
604 break;
605
606 case stylehint_BackColor:
607 *result = styles[style].bg;
608 break;
609
610 case stylehint_ReverseColor:
611 *result = styles[style].reverse;
612 break;
613
614 default:
615 return false;
616 }
617
618 return true;
619 }
620
glk_fileref_create_temp(uint usage,uint rock)621 frefid_t GlkAPI::glk_fileref_create_temp(uint usage, uint rock) {
622 return _streams->createTemp(usage, rock);
623 }
624
glk_fileref_create_by_name(uint usage,const char * name,uint rock)625 frefid_t GlkAPI::glk_fileref_create_by_name(uint usage, const char *name, uint rock) {
626 // Take out all dangerous characters
627 Common::String tempName(name);
628 for (uint idx = 0; idx < tempName.size(); ++idx) {
629 if (tempName[idx] == '/' || tempName[idx] == '\\' || tempName[idx] == ':')
630 tempName.setChar(idx, '-');
631 }
632
633 return _streams->createRef(tempName, usage, rock);
634 }
635
glk_fileref_create_by_prompt(uint usage,FileMode fmode,uint rock)636 frefid_t GlkAPI::glk_fileref_create_by_prompt(uint usage, FileMode fmode, uint rock) {
637 return _streams->createByPrompt(usage, fmode, rock);
638 }
639
glk_fileref_create_from_fileref(uint usage,frefid_t fref,uint rock)640 frefid_t GlkAPI::glk_fileref_create_from_fileref(uint usage, frefid_t fref, uint rock) {
641 if (!fref) {
642 warning("fileref_create_from_fileref: invalid ref");
643 return nullptr;
644 } else {
645 return _streams->createFromRef(fref, usage, rock);
646 }
647 }
648
glk_fileref_destroy(frefid_t fref)649 void GlkAPI::glk_fileref_destroy(frefid_t fref) {
650 _streams->deleteRef(fref);
651 }
652
glk_fileref_iterate(frefid_t fref,uint * rockptr)653 frefid_t GlkAPI::glk_fileref_iterate(frefid_t fref, uint *rockptr) {
654 return _streams->iterate(fref, rockptr);
655 }
656
glk_fileref_get_rock(frefid_t fref)657 uint GlkAPI::glk_fileref_get_rock(frefid_t fref) {
658 if (!fref) {
659 warning("fileref_get_rock: invalid ref.");
660 return 0;
661 } else {
662 return fref->_rock;
663 }
664 }
665
glk_fileref_delete_file(frefid_t fref)666 void GlkAPI::glk_fileref_delete_file(frefid_t fref) {
667 fref->deleteFile();
668 }
669
glk_fileref_does_file_exist(frefid_t fref)670 uint GlkAPI::glk_fileref_does_file_exist(frefid_t fref) {
671 return fref->exists();
672 }
673
glk_select(event_t * event)674 void GlkAPI::glk_select(event_t *event) {
675 if (!_gliFirstEvent) {
676 _windows->inputGuessFocus();
677 _gliFirstEvent = true;
678 }
679
680 _events->getEvent(event, false);
681 }
682
glk_select_poll(event_t * event)683 void GlkAPI::glk_select_poll(event_t *event) {
684 if (!_gliFirstEvent) {
685 _windows->inputGuessFocus();
686 _gliFirstEvent = true;
687 }
688
689 _events->getEvent(event, true);
690 }
691
glk_request_timer_events(uint millisecs)692 void GlkAPI::glk_request_timer_events(uint millisecs) {
693 _events->setTimerInterval(millisecs);
694 }
695
glk_request_line_event(winid_t win,char * buf,uint maxlen,uint initlen)696 void GlkAPI::glk_request_line_event(winid_t win, char *buf, uint maxlen, uint initlen) {
697 if (!win) {
698 warning("request_line_event: invalid ref");
699 } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
700 || win->_lineRequestUni) {
701 warning("request_line_event: window already has keyboard request");
702 } else {
703 win->requestLineEvent(buf, maxlen, initlen);
704 }
705 }
706
glk_request_char_event(winid_t win)707 void GlkAPI::glk_request_char_event(winid_t win) {
708 if (!win) {
709 warning("request_char_event: invalid ref");
710 } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
711 || win->_lineRequestUni) {
712 warning("request_char_event: window already has keyboard request");
713 } else {
714 win->requestCharEvent();
715 }
716 }
717
glk_request_mouse_event(winid_t win)718 void GlkAPI::glk_request_mouse_event(winid_t win) {
719 if (!win) {
720 warning("request_mouse_event: invalid ref");
721 } else {
722 win->requestMouseEvent();
723 }
724 }
725
glk_cancel_line_event(winid_t win,event_t * event)726 void GlkAPI::glk_cancel_line_event(winid_t win, event_t *event) {
727 if (!win) {
728 warning("cancel_line_event: invalid ref");
729 } else {
730 win->cancelLineEvent(event);
731 }
732 }
733
glk_cancel_char_event(winid_t win)734 void GlkAPI::glk_cancel_char_event(winid_t win) {
735 if (!win) {
736 warning("glk_cancel_char_event: invalid ref");
737 } else {
738 win->cancelCharEvent();
739 }
740 }
741
glk_cancel_mouse_event(winid_t win)742 void GlkAPI::glk_cancel_mouse_event(winid_t win) {
743 if (!win) {
744 warning("cancel_mouse_event: invalid ref");
745 } else {
746 win->cancelMouseEvent();
747 }
748 }
749
glk_set_echo_line_event(winid_t win,uint val)750 void GlkAPI::glk_set_echo_line_event(winid_t win, uint val) {
751 if (!win) {
752 warning("set_echo_line_event: invalid ref");
753 } else {
754 win->setEchoLineEvent(val);
755 }
756 }
757
glk_set_terminators_line_event(winid_t win,const uint32 * keycodes,uint count)758 void GlkAPI::glk_set_terminators_line_event(winid_t win, const uint32 *keycodes, uint count) {
759 if (!win) {
760 warning("set_terminators_line_event: invalid ref");
761 } else {
762 win->setTerminatorsLineEvent(keycodes, count);
763 }
764 }
765
glk_buffer_to_lower_case_uni(uint32 * buf,uint len,uint numchars)766 uint GlkAPI::glk_buffer_to_lower_case_uni(uint32 *buf, uint len, uint numchars) {
767 return bufferChangeCase(buf, len, numchars, CASE_LOWER, COND_ALL, true);
768 }
769
glk_buffer_to_upper_case_uni(uint32 * buf,uint len,uint numchars)770 uint GlkAPI::glk_buffer_to_upper_case_uni(uint32 *buf, uint len, uint numchars) {
771 return bufferChangeCase(buf, len, numchars, CASE_UPPER, COND_ALL, true);
772 }
773
glk_buffer_to_title_case_uni(uint32 * buf,uint len,uint numchars,uint lowerrest)774 uint GlkAPI::glk_buffer_to_title_case_uni(uint32 *buf, uint len,
775 uint numchars, uint lowerrest) {
776 return bufferChangeCase(buf, len, numchars, CASE_TITLE, COND_LINESTART, lowerrest);
777 }
778
glk_put_char_uni(uint32 ch)779 void GlkAPI::glk_put_char_uni(uint32 ch) {
780 _streams->getCurrent()->putCharUni(ch);
781 }
782
glk_put_string_uni(const uint32 * s)783 void GlkAPI::glk_put_string_uni(const uint32 *s) {
784 _streams->getCurrent()->putBufferUni(s, strlen_uni(s));
785 }
786
glk_put_buffer_uni(const uint32 * buf,uint len)787 void GlkAPI::glk_put_buffer_uni(const uint32 *buf, uint len) {
788 _streams->getCurrent()->putBufferUni(buf, len);
789 }
790
glk_put_char_stream_uni(strid_t str,uint32 ch)791 void GlkAPI::glk_put_char_stream_uni(strid_t str, uint32 ch) {
792 if (str) {
793 str->putCharUni(ch);
794 } else {
795 warning("put_char_stream_uni: invalid ref");
796 }
797 }
798
glk_put_string_stream_uni(strid_t str,const uint32 * s)799 void GlkAPI::glk_put_string_stream_uni(strid_t str, const uint32 *s) {
800 if (str) {
801 str->putBufferUni(s, strlen_uni(s));
802 } else {
803 warning("put_string_stream_uni: invalid ref");
804 }
805 }
806
glk_put_buffer_stream_uni(strid_t str,const uint32 * buf,uint len)807 void GlkAPI::glk_put_buffer_stream_uni(strid_t str, const uint32 *buf, uint len) {
808 if (str) {
809 str->putBufferUni(buf, len);
810 } else {
811 warning("put_buffer_stream_uni: invalid ref");
812 }
813 }
814
glk_get_char_stream_uni(strid_t str)815 int GlkAPI::glk_get_char_stream_uni(strid_t str) {
816 if (str) {
817 return str->getCharUni();
818 } else {
819 warning("get_char_stream_uni: invalid ref");
820 return -1;
821 }
822 }
823
glk_get_buffer_stream_uni(strid_t str,uint32 * buf,uint len)824 uint GlkAPI::glk_get_buffer_stream_uni(strid_t str, uint32 *buf, uint len) {
825 if (str) {
826 return str->getBufferUni(buf, len);
827 } else {
828 warning("get_buffer_stream_uni: invalid ref");
829 return 0;
830 }
831 }
832
glk_get_line_stream_uni(strid_t str,uint32 * buf,uint len)833 uint GlkAPI::glk_get_line_stream_uni(strid_t str, uint32 *buf, uint len) {
834 if (str) {
835 return str->getLineUni(buf, len);
836 } else {
837 warning("get_line_stream_uni: invalid ref");
838 return (uint) - 1;
839 }
840 }
841
glk_stream_open_file_uni(frefid_t fileref,FileMode fmode,uint rock)842 strid_t GlkAPI::glk_stream_open_file_uni(frefid_t fileref, FileMode fmode, uint rock) {
843 return _streams->openFileStream(fileref, fmode, rock, true);
844 }
845
glk_stream_open_memory_uni(uint32 * buf,uint buflen,FileMode fmode,uint rock)846 strid_t GlkAPI::glk_stream_open_memory_uni(uint32 *buf, uint buflen, FileMode fmode, uint rock) {
847 return _streams->openMemoryStream(buf, buflen, fmode, rock, true);
848 }
849
glk_request_char_event_uni(winid_t win)850 void GlkAPI::glk_request_char_event_uni(winid_t win) {
851 if (!win) {
852 warning("request_char_event_uni: invalid ref");
853 } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
854 || win->_lineRequestUni) {
855 warning("request_char_event_uni: window already has keyboard request");
856 } else {
857 win->requestCharEvent();
858 }
859 }
860
glk_request_line_event_uni(winid_t win,uint32 * buf,uint maxlen,uint initlen)861 void GlkAPI::glk_request_line_event_uni(winid_t win, uint32 *buf, uint maxlen, uint initlen) {
862 if (!win) {
863 warning("request_line_event_uni: invalid ref");
864 } else if (win->_charRequest || win->_lineRequest || win->_charRequestUni
865 || win->_lineRequestUni) {
866 warning("request_line_event_uni: window already has keyboard request");
867 } else {
868 win->requestLineEventUni(buf, maxlen, initlen);
869 }
870 }
871
glk_buffer_canon_decompose_uni(uint32 * buf,uint len,uint numchars)872 uint GlkAPI::glk_buffer_canon_decompose_uni(uint32 *buf, uint len, uint numchars) {
873 // TODO
874 return 0;
875 }
876
glk_buffer_canon_normalize_uni(uint32 * buf,uint len,uint numchars)877 uint GlkAPI::glk_buffer_canon_normalize_uni(uint32 *buf, uint len, uint numchars) {
878 return 0;
879 }
880
glk_image_draw(winid_t win,uint image,int val1,int val2)881 bool GlkAPI::glk_image_draw(winid_t win, uint image, int val1, int val2) {
882 if (!win) {
883 warning("image_draw: invalid ref");
884 } else if (g_conf->_graphics) {
885 TextBufferWindow *textWin = dynamic_cast<TextBufferWindow *>(win);
886 GraphicsWindow *gfxWin = dynamic_cast<GraphicsWindow *>(win);
887
888 if (textWin)
889 return textWin->drawPicture(image, val1, false, 0, 0);
890 else if (gfxWin)
891 return gfxWin->drawPicture(image, val1, val2, false, 0, 0);
892 }
893
894 return false;
895 }
896
glk_image_draw_scaled(winid_t win,uint image,int val1,int val2,uint width,uint height)897 bool GlkAPI::glk_image_draw_scaled(winid_t win, uint image, int val1, int val2,
898 uint width, uint height) {
899 if (!win) {
900 warning("image_draw_scaled: invalid ref");
901 } else if (g_conf->_graphics) {
902 TextBufferWindow *textWin = dynamic_cast<TextBufferWindow *>(win);
903 GraphicsWindow *gfxWin = dynamic_cast<GraphicsWindow *>(win);
904
905 if (textWin)
906 return textWin->drawPicture(image, val1, true, width, height);
907 else if (gfxWin)
908 return gfxWin->drawPicture(image, val1, val2, true, width, height);
909 }
910
911 return false;
912 }
913
glk_image_get_info(uint image,uint * width,uint * height)914 bool GlkAPI::glk_image_get_info(uint image, uint *width, uint *height) {
915 if (!g_conf->_graphics)
916 return false;
917
918 Picture *pic = g_vm->_pictures->load(image);
919 if (!pic)
920 return false;
921
922 if (width)
923 *width = pic->w;
924 if (height)
925 *height = pic->h;
926
927 return true;
928 }
929
glk_window_flow_break(winid_t win)930 void GlkAPI::glk_window_flow_break(winid_t win) {
931 if (!win) {
932 warning("window_erase_rect: invalid ref");
933 } else {
934 win->flowBreak();
935 }
936 }
937
glk_window_erase_rect(winid_t win,int left,int top,uint width,uint height)938 void GlkAPI::glk_window_erase_rect(winid_t win, int left, int top, uint width, uint height) {
939 if (!win) {
940 warning("window_erase_rect: invalid ref");
941 } else {
942 win->eraseRect(false, Rect(left, top, left + width, top + height));
943 }
944 }
945
glk_window_fill_rect(winid_t win,uint color,int left,int top,uint width,uint height)946 void GlkAPI::glk_window_fill_rect(winid_t win, uint color, int left, int top,
947 uint width, uint height) {
948 if (!win) {
949 warning("window_fill_rect: invalid ref");
950 } else {
951 win->eraseRect(color, Rect(left, top, left + width, top + height));
952 }
953 }
954
glk_window_set_background_color(winid_t win,uint color)955 void GlkAPI::glk_window_set_background_color(winid_t win, uint color) {
956 if (!win) {
957 warning("window_set_background_color: invalid ref");
958 } else {
959 win->setBackgroundColor(color);
960 }
961 }
962
glk_schannel_create(uint rock)963 schanid_t GlkAPI::glk_schannel_create(uint rock) {
964 return _sounds->create(rock);
965 }
966
glk_schannel_destroy(schanid_t chan)967 void GlkAPI::glk_schannel_destroy(schanid_t chan) {
968 if (chan) {
969 delete chan;
970 } else {
971 warning("schannel_dest roy: invalid ref");
972 }
973 }
974
glk_schannel_iterate(schanid_t chan,uint * rockptr)975 schanid_t GlkAPI::glk_schannel_iterate(schanid_t chan, uint *rockptr) {
976 return _sounds->iterate(chan, rockptr);
977 }
978
glk_schannel_get_rock(schanid_t chan)979 uint GlkAPI::glk_schannel_get_rock(schanid_t chan) {
980 if (chan) {
981 return chan->_rock;
982 } else {
983 warning("schannel_get_rock: invalid ref");
984 return 0;
985 }
986 }
987
glk_schannel_play(schanid_t chan,uint snd)988 uint GlkAPI::glk_schannel_play(schanid_t chan, uint snd) {
989 if (chan) {
990 return chan->play(snd);
991 } else {
992 warning("schannel_play_ext: invalid ref");
993 return 0;
994 }
995 }
996
glk_schannel_play_ext(schanid_t chan,uint snd,uint repeats,uint notify)997 uint GlkAPI::glk_schannel_play_ext(schanid_t chan, uint snd, uint repeats, uint notify) {
998 if (chan) {
999 return chan->play(snd, repeats, notify);
1000 } else {
1001 warning("schannel_play_ext: invalid ref");
1002 return 0;
1003 }
1004 }
1005
glk_schannel_stop(schanid_t chan)1006 void GlkAPI::glk_schannel_stop(schanid_t chan) {
1007 if (chan) {
1008 chan->stop();
1009 } else {
1010 warning("schannel_stop: invalid ref");
1011 }
1012 }
1013
glk_schannel_set_volume(schanid_t chan,uint vol)1014 void GlkAPI::glk_schannel_set_volume(schanid_t chan, uint vol) {
1015 if (chan) {
1016 chan->setVolume(vol);
1017 } else {
1018 warning("schannel_set_volume: invalid ref");
1019 }
1020 }
1021
glk_sound_load_hint(uint snd,uint flag)1022 void GlkAPI::glk_sound_load_hint(uint snd, uint flag) {
1023 // No implementation
1024 }
1025
glk_schannel_create_ext(uint rock,uint volume)1026 schanid_t GlkAPI::glk_schannel_create_ext(uint rock, uint volume) {
1027 // No implementation
1028 return nullptr;
1029 }
1030
glk_schannel_play_multi(schanid_t * chanarray,uint chancount,uint * sndarray,uint soundcount,uint notify)1031 uint GlkAPI::glk_schannel_play_multi(schanid_t *chanarray, uint chancount,
1032 uint *sndarray, uint soundcount, uint notify) {
1033 // No implementation
1034 return 0;
1035 }
1036
glk_schannel_pause(schanid_t chan)1037 void GlkAPI::glk_schannel_pause(schanid_t chan) {
1038 if (chan) {
1039 chan->pause();
1040 } else {
1041 warning("schannel_pause: invalid ref");
1042 }
1043 }
1044
glk_schannel_unpause(schanid_t chan)1045 void GlkAPI::glk_schannel_unpause(schanid_t chan) {
1046 if (chan) {
1047 chan->unpause();
1048 } else {
1049 warning("schannel_unpause: invalid ref");
1050 }
1051 }
1052
glk_schannel_set_volume_ext(schanid_t chan,uint vol,uint duration,uint notify)1053 void GlkAPI::glk_schannel_set_volume_ext(schanid_t chan, uint vol,
1054 uint duration, uint notify) {
1055 if (chan) {
1056 chan->setVolume(vol, duration, notify);
1057 } else {
1058 warning("schannel_set_volume_ext: invalid ref");
1059 }
1060 }
1061
glk_set_hyperlink(uint linkval)1062 void GlkAPI::glk_set_hyperlink(uint linkval) {
1063 _streams->getCurrent()->setHyperlink(linkval);
1064 }
1065
glk_set_hyperlink_stream(strid_t str,uint linkval)1066 void GlkAPI::glk_set_hyperlink_stream(strid_t str, uint linkval) {
1067 if (str)
1068 str->setHyperlink(linkval);
1069 }
1070
glk_request_hyperlink_event(winid_t win)1071 void GlkAPI::glk_request_hyperlink_event(winid_t win) {
1072 if (!win) {
1073 warning("request_hyperlink_event: invalid ref");
1074 } else {
1075 win->requestHyperlinkEvent();
1076 }
1077 }
1078
glk_cancel_hyperlink_event(winid_t win)1079 void GlkAPI::glk_cancel_hyperlink_event(winid_t win) {
1080 if (win) {
1081 win->cancelHyperlinkEvent();
1082 } else {
1083 warning("cancel_hyperlink_event: invalid ref");
1084 }
1085 }
1086
1087 /*--------------------------------------------------------------------------*/
1088
glk_current_time(glktimeval_t * time)1089 void GlkAPI::glk_current_time(glktimeval_t *time) {
1090 TimeAndDate td;
1091 *time = td;
1092 }
1093
glk_current_simple_time(uint factor)1094 int GlkAPI::glk_current_simple_time(uint factor) {
1095 assert(factor);
1096 TimeAndDate td;
1097
1098 return td / factor;
1099 }
1100
glk_time_to_date_utc(const glktimeval_t * time,glkdate_t * date)1101 void GlkAPI::glk_time_to_date_utc(const glktimeval_t *time, glkdate_t *date) {
1102 // TODO: timezones aren't currently supported
1103 *date = TimeAndDate(*time);
1104 }
1105
glk_time_to_date_local(const glktimeval_t * time,glkdate_t * date)1106 void GlkAPI::glk_time_to_date_local(const glktimeval_t *time, glkdate_t *date) {
1107 *date = TimeAndDate(*time);
1108 }
1109
glk_simple_time_to_date_utc(int time,uint factor,glkdate_t * date)1110 void GlkAPI::glk_simple_time_to_date_utc(int time, uint factor, glkdate_t *date) {
1111 TimeSeconds secs = (int64)time * factor;
1112 *date = TimeAndDate(secs);
1113 }
1114
glk_simple_time_to_date_local(int time,uint factor,glkdate_t * date)1115 void GlkAPI::glk_simple_time_to_date_local(int time, uint factor, glkdate_t *date) {
1116 TimeSeconds secs = (int64)time * factor;
1117 *date = TimeAndDate(secs);
1118 }
1119
glk_date_to_time_utc(const glkdate_t * date,glktimeval_t * time)1120 void GlkAPI::glk_date_to_time_utc(const glkdate_t *date, glktimeval_t *time) {
1121 // WORKAROUND: timezones aren't currently supported
1122 *time = TimeAndDate(*date);
1123 }
1124
glk_date_to_time_local(const glkdate_t * date,glktimeval_t * time)1125 void GlkAPI::glk_date_to_time_local(const glkdate_t *date, glktimeval_t *time) {
1126 *time = TimeAndDate(*date);
1127 }
1128
glk_date_to_simple_time_utc(const glkdate_t * date,uint factor)1129 int GlkAPI::glk_date_to_simple_time_utc(const glkdate_t *date, uint factor) {
1130 // WORKAROUND: timezones aren't currently supported
1131 assert(factor);
1132 TimeSeconds ts = TimeAndDate(*date);
1133 return ts / factor;
1134 }
1135
glk_date_to_simple_time_local(const glkdate_t * date,uint factor)1136 int GlkAPI::glk_date_to_simple_time_local(const glkdate_t *date, uint factor) {
1137 assert(factor);
1138 TimeSeconds ts = TimeAndDate(*date);
1139 return ts / factor;
1140 }
1141
1142 /*--------------------------------------------------------------------------*/
1143
1144 /* XXX non-official Glk functions */
1145
garglk_fileref_get_name(frefid_t fref) const1146 const char *GlkAPI::garglk_fileref_get_name(frefid_t fref) const {
1147 return fref->_filename.c_str();
1148 }
1149
garglk_set_program_name(const char * name)1150 void GlkAPI::garglk_set_program_name(const char *name) {
1151 // Program name isn't displayed
1152 }
1153
garglk_set_program_info(const char * info)1154 void GlkAPI::garglk_set_program_info(const char *info) {
1155 // Program info isn't displayed
1156 }
1157
garglk_set_story_name(const char * name)1158 void GlkAPI::garglk_set_story_name(const char *name) {
1159 // Story name isn't displayed
1160 }
1161
garglk_set_story_title(const char * title)1162 void GlkAPI::garglk_set_story_title(const char *title) {
1163 // Story title isn't displayed
1164 }
1165
garglk_set_config(const char * name)1166 void GlkAPI::garglk_set_config(const char *name) {
1167 // No implementation
1168 }
1169
garglk_unput_string(const char * str)1170 void GlkAPI::garglk_unput_string(const char *str) {
1171 _streams->getCurrent()->unputBuffer(str, strlen(str));
1172 }
1173
garglk_unput_string_uni(const uint32 * str)1174 void GlkAPI::garglk_unput_string_uni(const uint32 *str) {
1175 _streams->getCurrent()->unputBufferUni(str, strlen_uni(str));
1176 }
1177
garglk_set_zcolors(uint fg,uint bg)1178 void GlkAPI::garglk_set_zcolors(uint fg, uint bg) {
1179 _streams->getCurrent()->setZColors(fg, bg);
1180 }
1181
garglk_set_zcolors_stream(strid_t str,uint fg,uint bg)1182 void GlkAPI::garglk_set_zcolors_stream(strid_t str, uint fg, uint bg) {
1183 if (str) {
1184 str->setZColors(fg, bg);
1185 } else {
1186 warning("set_style_stream: Invalid ref");
1187 }
1188 }
1189
garglk_set_reversevideo(uint reverse)1190 void GlkAPI::garglk_set_reversevideo(uint reverse) {
1191 _streams->getCurrent()->setReverseVideo(reverse != 0);
1192 }
1193
garglk_set_reversevideo_stream(strid_t str,uint reverse)1194 void GlkAPI::garglk_set_reversevideo_stream(strid_t str, uint reverse) {
1195 if (str) {
1196 str->setReverseVideo(reverse != 0);
1197 } else {
1198 warning("set_reversevideo: Invalid ref");
1199 }
1200 }
1201
garglk_window_get_cursor(winid_t win,uint * xpos,uint * ypos)1202 void GlkAPI::garglk_window_get_cursor(winid_t win, uint *xpos, uint *ypos) {
1203 Point pos = win->getCursor();
1204 *xpos = pos.x;
1205 *ypos = pos.y;
1206 }
1207
garglk_window_get_cursor_current(uint * xpos,uint * ypos)1208 void GlkAPI::garglk_window_get_cursor_current(uint *xpos, uint *ypos) {
1209 garglk_window_get_cursor(_windows->getFocusWindow(), xpos, ypos);
1210 }
1211
1212 } // End of namespace Glk
1213