#include #include #include #include "addrs.h" #include "screen.h" #include "edbox.h" #include "keyclick.h" #include "complete.h" /* TODO: tab completion */ char *old_edbox[EDBOX_SIZE]; static u16 old_len; static int typeover; int edbox_visible = 0; static u16 edbox_pos; /* range 0 to EDBOX_SIZE - 1 */ u16 edbox_len; /* idem */ void (*edbox_callback)(void); static void hide_cursor(void) { edit_box[edbox_pos] &= 0x7f; } static void show_cursor(void) { edit_box[edbox_pos] |= 0x80; } void edbox_clear(void) { memset(edit_box, 0, EDBOX_SIZE); edbox_pos = edbox_len = 0; show_cursor(); // not needed? seems it is.. } void edbox_show(void) { u16 addr; if(edbox_pos < 80) addr = (u16)edit_box; else addr = (u16)edit_box + edbox_pos - 79; scr_waitvcount(116); *dlist_status_lms = addr; *dlist_last_line = 0x02; /* ANTIC GR.0 */ edbox_visible = 1; show_cursor(); } void edbox_hide(void) { scr_end_scrollback(); /* exit Start+E mode */ edbox_visible = 0; scr_refresh(); } /* note: c will never be an EOL. idea: when the edbox is completely full (240 chars), go ahead and pretend the user pressed Return (call edbox_callback, etc). not sure if this is more or less annoying than just refusing to accept more input until Return is pressed. */ void edbox_putc(char c) { extern void __fastcall__ bell(void); if(!c) return; /* no inserting nulls */ if(!typeover) memmove(edit_box + edbox_pos + 1, edit_box + edbox_pos, EDBOX_SIZE - edbox_pos - 1); edit_box[edbox_pos] = c; if(edbox_pos < EDBOX_SIZE - 1) { edbox_pos++; edbox_len++; } else { bell(); } } static void copy_to_old(void) { if(!edbox_len) return; memcpy(old_edbox, edit_box, edbox_len); memset(old_edbox + edbox_len, 0, (EDBOX_SIZE - 1) - edbox_len); old_len = edbox_len; } static void restore_old(void) { edbox_clear(); hide_cursor(); memcpy(edit_box, old_edbox, old_len); edbox_pos = edbox_len = old_len; } static void fake_keystroke(char c) { keyclick(); OS.ch = 0xff; edbox_putc(c); } static void del_char(void) { if(!edbox_len) return; memmove(edit_box + edbox_pos, edit_box + edbox_pos + 1, EDBOX_SIZE - edbox_pos - 1); edbox_len--; } static void del_to_end(void) { while(edbox_len > edbox_pos) del_char(); } static void backspace(void) { if(!edbox_pos) return; edbox_pos--; del_char(); } static void up(void) { if(!edbox_len) { restore_old(); } else { if(edbox_pos > 39) edbox_pos -= 40; else edbox_pos = 0; } } static void down(void) { if(edbox_pos > 199) return; edbox_pos += 40; if(edbox_pos > edbox_len) edbox_pos = edbox_len; } static void word_left(char del) { if(!edbox_pos) return; if(!del) edbox_pos--; while(edbox_pos && edit_box[edbox_pos] == ' ') { if(del) del_char(); edbox_pos--; } while(edbox_pos && edit_box[edbox_pos] != ' ') { if(del) del_char(); edbox_pos--; } // XXX: what's this good for? if(del && !edbox_pos) edit_box[edbox_pos] = /* ' ' */ 0; } static void del_word(void) { word_left(1); } static void back_word(void) { word_left(0); } static void forward_word(void) { while(edbox_pos < edbox_len && edit_box[edbox_pos] == ' ') edbox_pos++; while(edbox_pos < edbox_len && edit_box[edbox_pos] != ' ') edbox_pos++; } static void del_to_start(void) { while(edbox_pos) backspace(); } static void normal_keystroke(void) { char c; c = cgetc(); if(c != CH_TAB) comp_complete_done(); switch(c) { case CH_EOL: // hide_cursor(); // already done by the caller copy_to_old(); edbox_hide(); if(edbox_callback) (*edbox_callback)(); edbox_clear(); break; case CH_CLR: edbox_hide(); /* fall thru */ case CH_DELLINE: edbox_clear(); break; case 0x15: /* ^U */ del_to_start(); break; case 0x0b: /* ^K */ del_to_end(); break; case CH_DEL: case 0x18: /* ^X */ if(!edbox_len) edbox_hide(); else backspace(); break; case 0x02: /* ^B */ back_word(); break; case 0x06: /* ^F */ forward_word(); break; case 0x17: /* ^W */ del_word(); break; case CH_CURS_LEFT: if(edbox_pos) edbox_pos--; break; case CH_CURS_RIGHT: if(edbox_pos < edbox_len) edbox_pos++; break; case CH_CURS_UP: up(); break; case CH_CURS_DOWN: down(); break; case CH_DELCHR: del_char(); break; case 0x01: /* ^A */ edbox_pos = 0; break; case 0x05: /* ^E */ edbox_pos = edbox_len; break; case CH_TAB: comp_complete(); break; case 0xff: /* ctrl-insert */ typeover = !typeover; break; default: edbox_putc(c); break; } } void edbox_keystroke(void) { extern char start_latch; extern void start_keystroke(void); char c; if(OS.ssflag) OS.ch = 0x9f; while(OS.ch == 0xff) ; /* filter out all ctrl-shift key combos except the ones we actually support */ if(OS.ch == 0xce) { /* ctrl-shift-up, same as ^B = back 1 word */ OS.ch = 0x95; } else if(OS.ch == 0xcf) { /* ctrl-shift-down, same as ^F = forward 1 word */ OS.ch = 0xb8; } else if(OS.ch > 0xbf) { OS.ch = 0xff; return; } /* keys we want to ignore or act on without showing the edbox */ switch(OS.ch) { case 0x1c: /* key: ESC */ keyclick(); start_latch = 1; return; case 0x9f: /* ctrl-1 (XXX: the OS traps this, we never see it!) */ case 0x9e: /* ctrl-2 */ case 0x9a: /* ctrl-3 (crash if cgetc() reads it!) */ case 0x98: /* ctrl-4 */ case 0x9d: /* ctrl-5 */ case 0x9b: /* ctrl-6 */ case 0xb3: /* ctrl-7 */ OS.ch &= 0x7f; start_latch = 1; start_keystroke(); return; case 0x6c: /* shift-tab */ case 0xac: /* ctrl-tab */ OS.ch = 0xff; /* ignore it! */ return; break; } edbox_show(); /* keys we want to act on, and show the edbox after */ c = 0; switch(OS.ch) { case 0xa0: /* key: ctrl [ */ c = 0x7b; /* ascii: { */ break; case 0xa2: /* key: ctrl ] */ c = 0x7d; /* ascii: } */ break; break; case 0x5c: /* key: shift ESC */ c = 0x60; /* ascii: ` */ break; case 0x9c: /* key: ctrl ESC */ c = 0x7e; /* ascii: ~ */ break; case 0x3c: /* caps */ case 0x7c: /* shift-caps */ case 0xbc: /* ctrl-caps */ OS.shflok ^= 0x40; keyclick(); return; break; case 0x27: /* atari key */ case 0x67: /* ...w/shift */ case 0xa7: /* ...w/ctrl */ c = 0x02; /* ^B = IRC bold formatting char */ break; default: break; } hide_cursor(); if(c) { fake_keystroke(c); } else { normal_keystroke(); } if(edbox_visible) edbox_show(); show_cursor(); } void edbox_addchr(char c) { edit_box[edbox_len++] = c; edbox_pos = edbox_len; } void edbox_space(void) { edbox_addchr(' '); } void edbox_set(char *contents) { edbox_clear(); while(*contents) { edit_box[edbox_len++] = *contents++; } edbox_pos = edbox_len; }