home *** CD-ROM | disk | FTP | other *** search
- /*
- * file "S5input.c"
- *
- * Borland C front end, input functions
- *
- */
-
- #include "frotz.h"
- #include "S5frotz.h"
- #include "S5api.h"
- #include "frotzs5.h"
-
- #ifndef HISTORY_BUFSIZE
- #define HISTORY_BUFSIZE 500
- #endif
-
- extern short is_terminator (struct sg *g, short);
-
- extern short read_yes_or_no (struct sg *g, const char *);
- extern void read_string (struct sg *g, short, zchar *);
-
- extern short completion (struct sg *g, const zchar *, zchar *);
-
- /*
- * switch_cursor
- *
- * Turn cursor on/off. If there is mouse support then turn the mouse
- * pointer on/off as well. The cursor should not be moved and the
- * contents of the screen should not be changed while the cursor is
- * visible (because of the primitive cursor emulation we use here).
- *
- */
-
- void switch_cursor (struct sg *g, short cursor)
- {
- SrvSwitchCursor(g,cursor);
- }/* switch_cursor */
-
- /*
- * get_key
- *
- * Read a keypress or a mouse click. Returns...
- *
- * ZC_TIME_OUT = time limit exceeded,
- * ZC_BACKSPACE = the backspace key,
- * ZC_RETURN = the return key,
- * ZC_HKEY_MIN...ZC_HKEY_MAX = a hot key,
- * ZC_ESCAPE = the escape key,
- * ZC_ASCII_MIN...ZC_ASCII_MAX = ASCII character,
- * ZC_ARROW_MIN...ZC_ARROW_MAX = an arrow key,
- * ZC_FKEY_MIN...ZC_FKEY_MAX = a function key,
- * ZC_NUMPAD_MIN...ZC_NUMPAD_MAX = a number pad key,
- * ZC_SINGLE_CLICK = single mouse click,
- * ZC_DOUBLE_CLICK = double mouse click,
- * ZC_LATIN1_MIN+1...ZC_LATIN1_MAX = ISO Latin-1 character,
- * SPECIAL_KEY_MIN...SPECIAL_KEY_MAX = a special editing key.
- *
- */
-
- short get_key (struct sg *g, short cursor)
- {
- unsigned short key;
-
- /* Loop until a key was pressed */
-
- if (cursor)
- switch_cursor (g,TRUE);
-
- for(;;) {
- key = SrvGetTimedCh(g,g->keytimeout);
- if(key == 0)
- break;
- if(key == 0x7F)
- key = SPECIAL_KEY_DELETE;
- if (key >= ZC_ASCII_MIN && key <= ZC_ASCII_MAX)
- break;
- if (key >= ZC_LATIN1_MIN && key <= ZC_LATIN1_MAX)
- break;
- if(key == ZC_INDENT)
- break;
- if (key == ZC_BACKSPACE)
- break;
- if (key == ZC_RETURN)
- break;
- if (key == ZC_ESCAPE)
- break;
- // EPOC cursor keys are translated to Frotz values as these
- // are sometimes handled directly by the interpreter
- if (key == ZC_EPOC_UP) {
- key = ZC_ARROW_UP;
- break;
- }
- if (key == ZC_EPOC_DOWN) {
- key = ZC_ARROW_DOWN;
- break;
- }
- if (key == ZC_EPOC_LEFT) {
- key = ZC_ARROW_LEFT;
- break;
- }
- if (key == ZC_EPOC_RIGHT) {
- key = ZC_ARROW_RIGHT;
- break;
- }
- if (key == SPECIAL_KEY_PAGE_UP) {
- key = ZC_ARROW_UP;
- break;
- }
- if (key == SPECIAL_KEY_PAGE_DOWN) {
- key = ZC_ARROW_DOWN;
- break;
- }
- if (key >= SPECIAL_KEY_MIN && key <= SPECIAL_KEY_MAX)
- break;
- switch(key)
- {
- case 18: case 16:
- case 19: case 21:
- case 14: case 24:
- case 4: goto hotkey;
- default:break;
- }
- }
-
- hotkey: if(key == 0)
- key = ZC_TIME_OUT;
-
- if (cursor)
- switch_cursor (g,FALSE);
-
- return key;
-
- }/* get_key */
-
- /*
- * cursor_left
- *
- * Move the cursor one character to the left.
- *
- */
-
- void cursor_left (struct sg *g)
- {
-
- if (g->input.pos > 0)
- {
- g->input.pos--;
- SrvSetCursor(g,--g->cursor_x, g->cursor_y);
- }
- }/* cursor_left */
-
- /*
- * cursor_right
- *
- * Move the cursor one character to the right.
- *
- */
-
- void cursor_right (struct sg *g)
- {
-
- if (g->input.pos < g->input.length)
- {
- g->input.pos++;
- SrvSetCursor(g,++g->cursor_x, g->cursor_y);
- }
-
- }/* cursor_right */
-
- /*
- * first_char
- *
- * Move the cursor to the beginning of the input line.
- *
- */
-
- void first_char (struct sg *g)
- {
-
- while (g->input.pos > 0)
- cursor_left (g);
-
- }/* first_char */
-
- /*
- * last_char
- *
- * Move the cursor to the end of the input line.
- *
- */
-
- void last_char (struct sg *g)
- {
-
- while (g->input.pos < g->input.length)
- cursor_right (g);
-
- }/* last_char */
-
- /*
- * prev_word
- *
- * Move the cursor to the start of the previous word.
- *
- */
-
- void prev_word (struct sg *g)
- {
-
- do {
-
- cursor_left (g);
-
- if (g->input.pos == 0)
- return;
-
- } while (g->input.buffer[g->input.pos] == ' ' || g->input.buffer[g->input.pos - 1] != ' ');
-
- }
-
- /* prev_word */
-
- /*
- * next_word
- *
- * Move the cursor to the start of the next word.
- *
- */
-
- void next_word (struct sg *g)
- {
-
- do {
-
- cursor_right (g);
-
- if (g->input.pos == g->input.length)
- return;
-
- } while (g->input.buffer[g->input.pos] == ' ' || g->input.buffer[g->input.pos - 1] != ' ');
-
- }
-
- /* next_word */
-
- /*
- * input_move
- *
- * Helper function to move parts of the input buffer:
- *
- * newc != 0, oldc == 0: INSERT
- * newc != 0, oldc != 0: OVERWRITE
- * newc == 0, oldc != 0: DELETE
- * newc == 0, oldc == 0: NO OPERATION
- *
- */
-
- #define H(x) (x ? 1 : 0)
-
- void input_move (struct sg *g, zchar newc, zchar oldc)
- {
- short newwidth = (newc != 0) ? 1 : 0;
- short oldwidth = (oldc != 0) ? 1 : 0;
-
- zchar *p = g->input.buffer + g->input.pos;
-
- short saved_x = g->cursor_x;
-
- short updated_width = g->input.width + newwidth - oldwidth;
- short updated_length = g->input.length + H (newc) - H (oldc);
-
- if (updated_width > g->input.max_width)
- return;
- if (updated_length > g->input.max_length)
- return;
-
- g->input.width = updated_width;
- g->input.length = updated_length;
-
- if (oldc != 0 && newc == 0)
- Srvmemmove (p, p + 1, updated_length - g->input.pos + 1);
- if (newc != 0 && oldc == 0)
- Srvmemmove (p + 1, p, updated_length - g->input.pos);
-
- if (newc != 0)
- *p = newc;
-
- os_display_string (g,p);
-
- switch_scrn_attr (g,TRUE);
-
- if (oldwidth > newwidth)
-
- os_erase_area (g,
- g->cursor_y + 1,
- g->cursor_x + 1,
- g->cursor_y + g->h_font_height,
- g->cursor_x + oldwidth - newwidth);
-
- switch_scrn_attr (g,FALSE);
-
- g->cursor_x = saved_x;
-
- if (newc != 0)
- cursor_right (g);
-
- }/* input_move */
-
- //#undef H(x)
-
- /*
- * delete_char
- *
- * Delete the character below the cursor.
- *
- */
-
- void delete_char (struct sg *g)
- {
-
- input_move (g,0, g->input.buffer[g->input.pos]);
- SrvSetCursor(g,g->cursor_x, g->cursor_y);
-
- }/* delete_char */
-
- /*
- * delete_left
- *
- * Delete the character to the left of the cursor.
- *
- */
-
- void delete_left (struct sg *g)
- {
-
- if (g->input.pos > 0) {
- cursor_left (g);
- delete_char (g);
- }
-
- }/* delete_left */
-
- /*
- * truncate_line
- *
- * Truncate the input line to n characters.
- *
- */
-
- void truncate_line (struct sg *g, short n)
- {
-
- last_char (g);
-
- while (g->input.length > n)
- delete_left (g);
-
- }/* truncate_line */
-
- /*
- * insert_char
- *
- * Insert a character into the input buffer.
- *
- */
-
- void insert_char (struct sg *g, zchar newc)
- {
- zchar oldc = 0;
-
- if (g->overwrite)
- oldc = g->input.buffer[g->input.pos];
-
- input_move (g,newc, oldc);
-
- }/* insert_char */
-
- /*
- * insert_string
- *
- * Add a string of characters to the input line.
- *
- */
-
- void insert_string (struct sg *g, const zchar *s)
- {
-
- while (*s != 0) {
-
- if (g->input.length + 1 > g->input.max_length)
- break;
- if (g->input.width + 1 > g->input.max_width)
- break;
-
- insert_char (g,*s++);
-
- }
-
- }/* insert_string */
-
- /*
- * tabulator_key
- *
- * Complete the word at the end of the input line, if possible.
- *
- */
-
- void tabulator_key (struct sg *g)
- {
- short status;
-
- if (g->input.pos == g->input.length) {
-
- zchar extension[10];
-
- status = completion (g,g->input.buffer, extension);
- insert_string (g,extension);
-
- } else status = 2;
-
- /* Beep if the completion was impossible or ambiguous */
-
- }/* tabulator_key */
-
- /*
- * store_input
- *
- * Copy the current input line to the history buffer.
- *
- */
-
- void store_input (struct sg *g)
- {
-
- if (g->input.length >= HISTORY_MIN_ENTRY) {
-
- const zchar *ptr = g->input.buffer;
-
- do {
-
- if (g->history.latest++ == HISTORY_BUFSIZE - 1)
- g->history.latest = 0;
-
- g->history.buffer[g->history.latest] = *ptr;
-
- } while (*ptr++ != 0);
-
- }
-
- }/* store_input */
-
- /*
- * fetch_entry
- *
- * Copy the current history entry to the input buffer and check if it
- * matches the prefix in the input buffer.
- *
- */
-
- short fetch_entry (struct sg *g, zchar *buf, short entry)
- {
- short i = 0;
-
- zchar c;
-
- do {
-
- if (entry++ == HISTORY_BUFSIZE - 1)
- entry = 0;
-
- c = g->history.buffer[entry];
-
- if (i < g->history.prefix_len && g->input.buffer[i] != c)
- return FALSE;
-
- buf[i++] = c;
-
- } while (c != 0);
-
- return (i > g->history.prefix_len) && (i > 1);
-
- }/* fetch_entry */
-
- /*
- * get_prev_entry
- *
- * Copy the previous history entry to the input buffer.
- *
- */
-
- void get_prev_entry (struct sg *g)
- {
- zchar buf[INPUT_BUFFER_SIZE];
-
- short i = g->history.current;
-
- do {
-
- do {
-
- if (i-- == 0)
- i = HISTORY_BUFSIZE - 1;
-
- if (i == g->history.latest)
- return;
-
- } while (g->history.buffer[i] != 0);
-
- } while (!fetch_entry (g,buf, i));
-
- truncate_line (g,g->history.prefix_len);
-
- insert_string (g,buf + g->history.prefix_len);
-
- g->history.current = i;
-
- }/* get_prev_entry */
-
- /*
- * get_next_entry
- *
- * Copy the next history entry to the input buffer.
- *
- */
-
- void get_next_entry (struct sg *g)
- {
- zchar buf[INPUT_BUFFER_SIZE];
-
- short i = g->history.current;
-
- truncate_line (g,g->history.prefix_len);
-
- do {
-
- do {
-
- if (i == g->history.latest)
- return;
-
- if (i++ == HISTORY_BUFSIZE - 1)
- i = 0;
-
- } while (g->history.buffer[i] != 0);
-
- if (i == g->history.latest)
- goto no_further;
-
- } while (!fetch_entry (g,buf, i));
-
- insert_string (g,buf + g->history.prefix_len);
-
- no_further:
-
- g->history.current = i;
-
- }/* get_next_entry */
-
- /*
- * os_read_line
- *
- * Read a line of input from the keyboard into a buffer. The buffer
- * may already be primed with some text. In this case, the "initial"
- * text is already displayed on the screen. After the input action
- * is complete, the function returns with the terminating key value.
- * The length of the input should not exceed "max" characters plus
- * an extra 0 terminator.
- *
- * Terminating keys are the return key (13) and all function keys
- * (see the Specification of the Z-machine) which are accepted by
- * the is_terminator function. Mouse clicks behave like function
- * keys except that the mouse position is stored in global variables
- * "mouse_x" and "mouse_y" (top left coordinates are (1,1)).
- *
- * Furthermore, Frotz introduces some special terminating keys:
- *
- * ZC_HKEY_PLAYBACK (Alt-P)
- * ZC_HKEY_RECORD (Alt-R)
- * ZC_HKEY_SEED (Alt-S)
- * ZC_HKEY_UNDO (Alt-U)
- * ZC_HKEY_RESTART (Alt-N, "new game")
- * ZC_HKEY_QUIT (Alt-X, "exit game")
- * ZC_HKEY_DEBUGGING (Alt-D)
- * ZC_HKEY_HELP (Alt-H)
- *
- * If the timeout argument is not zero, the input gets interrupted
- * after timeout/10 seconds (and the return value is 0).
- *
- * The complete input line including the cursor must fit in "width"
- * screen units.
- *
- * The function may be called once again to continue after timeouts,
- * misplaced mouse clicks or hot keys. In this case the "continued"
- * flag will be set. This information can be useful if the interface
- * implements input line history.
- *
- * The screen is not scrolled after the return key was pressed. The
- * cursor is at the end of the input line when the function returns.
- *
- * Since Inform 2.2 the helper function "completion" can be called
- * to implement word completion (similar to tcsh under Unix).
- *
- */
-
- #define new_history_search() \
- { g->history.prefix_len = g->input.pos; g->history.current = g->history.latest; }
-
- zchar os_read_line (struct sg *g, short max, zchar *buf, short timeout, short width, short continued)
- {
- short key = continued ? 9999 : 0;
-
- /* Initialise input variables */
- g->input.buffer = buf;
- g->input.pos = Srvstrlen ((char *) buf);
- g->input.length = Srvstrlen ((char *) buf);
- g->input.max_length = max;
- g->input.width = os_string_width (g,buf);
- g->input.max_width = width - 1;
-
- /* Calculate time limit */
-
- g->keytimeout = timeout;
-
- /* Loop until a terminator is found */
-
- do {
-
- if (key != 9999)
- new_history_search ();
-
- /* Get next key from mouse or keyboard */
-
- key = get_key (g,TRUE);
-
- if (key < ZC_ASCII_MIN || key > ZC_ASCII_MAX && key < ZC_LATIN1_MIN || key > ZC_LATIN1_MAX) {
-
- /* Ignore time-outs if the cursor is not at end of the line */
-
- if (key == ZC_TIME_OUT && g->input.pos < g->input.length)
- key = 9999;
-
- /* Backspace, return and escape keys */
-
- if (key == ZC_BACKSPACE)
- delete_left (g);
- if (key == ZC_RETURN)
- store_input (g);
- if (key == ZC_ESCAPE)
- truncate_line (g,0);
-
- /* Editing keys */
-
- if (g->cwin == 0) {
-
- if (key == ZC_ARROW_UP)
- get_prev_entry (g);
- if (key == ZC_ARROW_DOWN)
- get_next_entry (g);
- if (key == ZC_ARROW_LEFT)
- cursor_left (g);
- if (key == ZC_ARROW_RIGHT)
- cursor_right (g);
- if (key == ZC_INDENT)
- tabulator_key (g);
-
- // Test for all 4 cursor keys
- if (key >= ZC_ARROW_MIN && key <= ZC_ARROW_MAX)
- key = 9999;
-
- if (key == SPECIAL_KEY_HOME)
- first_char (g);
- if (key == SPECIAL_KEY_END)
- last_char (g);
- if (key == SPECIAL_KEY_DELETE)
- delete_char (g);
- if (key == SPECIAL_KEY_WORD_LEFT)
- prev_word (g);
- if (key == SPECIAL_KEY_WORD_RIGHT)
- next_word (g);
- /*if (key == SPECIAL_KEY_INSERT)
- overwrite = !overwrite;*/
-
- }
-
- } else insert_char (g,(unsigned char)key);
-
- } while (key > 0xff || !is_terminator (g,key));
-
- last_char (g);
-
- g->overwrite = FALSE;
-
- /* Return terminating key */
-
- return (unsigned char)key;
-
- }/* os_read_line */
-
- //#undef new_history_search()
-
- /*
- * os_read_key
- *
- * Read a single character from the keyboard (or a mouse click) and
- * return it. Input aborts after timeout/10 seconds.
- *
- */
-
- zchar os_read_key (struct sg *g, short timeout, short cursor)
- {
- short key;
-
- g->keytimeout = timeout;
-
- do {
-
- key = get_key (g,cursor);
-
- } while (key > 0xff);
-
- return (unsigned char)key;
-
- }/* os_read_key */
-
- /*
- * os_read_file_name
- *
- * Return the name of a file. Flag can be one of:
- *
- * FILE_SAVE - Save game file
- * FILE_RESTORE - Restore game file
- * FILE_SCRIPT - Transscript file
- * FILE_RECORD - Command file for recording
- * FILE_PLAYBACK - Command file for playback
- * FILE_SAVE_AUX - Save auxilary ("preferred settings") file
- * FILE_LOAD_AUX - Load auxilary ("preferred settings") file
- *
- * The length of the file name is limited by MAX_FILE_NAME. Ideally
- * an interpreter should open a file requester to ask for the file
- * name. If it is unable to do that then this function should call
- * print_string and read_string to ask for a file name.
- *
- */
-
- short os_read_file_name (struct sg *g, char *file_name, const char *default_name, short flag)
- {
- char *extension;
- // FILE *fp;
- short result;
-
- short saved_replay = g->istream_replay;
- short saved_record = g->ostream_record;
-
- /* Turn off playback and recording temporarily */
-
- g->istream_replay = FALSE;
- g->ostream_record = FALSE;
-
- /* Select appropriate extension */
-
- extension = ".aux";
-
- if (flag == FILE_SAVE || flag == FILE_RESTORE)
- extension = ".sav";
- if (flag == FILE_SCRIPT)
- extension = ".scr";
- if (flag == FILE_RECORD || flag == FILE_PLAYBACK)
- extension = ".rec";
-
- /* Input file name (reserve four bytes for a file name extension) */
-
- /* print_string ("Enter file name (\"");
- print_string (extension);
- print_string ("\" will be added).\nDefault is \"");
- print_string (default_name);
- print_string ("\": ");
-
- read_string (MAX_FILE_NAME - 4, (zchar *) file_name);*/
- Srvstrcpy(file_name,default_name);
- if (flag == FILE_SAVE || flag == FILE_RECORD || flag == FILE_SAVE_AUX)
- {
- if(!SrvDlgSave(g,((CFrotzAppUi *)(g->papp))->savepath, file_name))
- {
- result = FALSE;
- goto finished;
- }
- }
- else
- {
- if(!SrvDlgOpen(g,((CFrotzAppUi *)(g->papp))->savepath, file_name))
- {
- result = FALSE;
- goto finished;
- }
- }
-
- /* Use the default name if nothing was typed */
-
- /*if (file_name[0] == 0)
- Srvstrcpy (file_name, default_name);
- if (Srvstrchr (file_name, '.') == NULL)
- Srvstrcat (file_name, extension);*/
-
- /* Make sure it is safe to use this file name */
-
- result = TRUE;
-
-
- finished:
-
- /* Restore state of playback and recording */
-
- g->istream_replay = saved_replay;
- g->ostream_record = saved_record;
-
- return result;
-
- }/* os_read_file_name */
-