U0 InputFilterTask() { CJob *tmpc, *tmpc1; Bool old_filter; I64 old_flags = RFlagsGet; Fs->win_inhibit = WIG_USER_TASK_DEFAULT; LBts(&Fs->task_flags, TASKf_INPUT_FILTER_TASK); old_filter = LBts(&Fs->last_input_filter_task->task_flags, TASKf_FILTER_INPUT); LBEqual(&Fs->task_flags, TASKf_FILTER_INPUT, old_filter); while (TRUE) { CLI JobsHandler(old_flags); tmpc1 = &Fs->server_ctrl.next_waiting; tmpc = tmpc1->next; if (tmpc == tmpc1) break; else { if (tmpc->job_code == JOBT_TEXT_INPUT) { QueueRemove(tmpc); RFlagsSet(old_flags); try ExePrint("%s", tmpc->aux_str); catch Fs->catch_except = TRUE; JobDel(tmpc); } else break; } } Fs->next_input_filter_task->last_input_filter_task = Fs->last_input_filter_task; Fs->last_input_filter_task->next_input_filter_task = Fs->next_input_filter_task; if (!old_filter) LBtr(&Fs->last_input_filter_task->task_flags, TASKf_FILTER_INPUT); RFlagsSet(old_flags); } I64 MessageScan(I64 *_arg1=NULL, I64 *_arg2=NULL, I64 mask=~1, CTask *task=NULL) {/*Check for a message of type specified by a one in the mask. Throw-out messages not in mask. If no message fit mask, return NULL immediately. Remove desired message, return message_code. Note: This delivers messages from parent down to pop-up. */ I64 res, old_flags; CJob *tmpc, *tmpc1; if (!task) task = Fs; old_flags = RFlagsGet; tmpc1 =&task->server_ctrl.next_waiting; while (TRUE) { CLI if (task == Fs) JobsHandler(old_flags); tmpc = tmpc1->next; if (tmpc == tmpc1) break; else { if (tmpc->job_code == JOBT_MESSAGE) { QueueRemove(tmpc); RFlagsSet(old_flags); res = tmpc->message_code; if (_arg1) *_arg1 = tmpc->aux1; if (_arg2) *_arg2 = tmpc->aux2; JobDel(tmpc); if ((res != MESSAGE_KEY_DOWN || !(tmpc->aux2 & SCF_KEY_DESC) || !Bt(&task->win_inhibit, WIf_SELF_KEY_DESC)) && Bt(&mask, res)) goto sm_done; } } RFlagsSet(old_flags); } res = MESSAGE_NULL; if (_arg1) *_arg1 = 0; if (_arg2) *_arg2 = 0; if (task->parent_task && task->parent_task->popup_task == task) { RFlagsSet(old_flags); return MessageScan(_arg1, _arg2, mask, task->parent_task); } sm_done: RFlagsSet(old_flags); return res; } I64 FlushMessages(CTask *task=NULL) {//Throw away all messages. Return count. I64 res = 0, arg1, arg2; while (MessageScan(&arg1, &arg2, ~1, task)) res++; return res; } I64 MessageGet(I64 *_arg1=NULL, I64 *_arg2=NULL, I64 mask=~1, CTask *task=NULL) {//Wait for a message of type specified by a one in the mask. //Throw-out all messages not in mask. //Returns message_code. See ::/Demo/MessageLoop.ZC. I64 res; if (!task) task = Fs; LBtr(&task->task_flags, TASKf_IDLE); while (!(res = MessageScan(_arg1, _arg2, mask, task))) { LBts(&task->task_flags, TASKf_IDLE); Yield; } LBtr(&task->task_flags, TASKf_IDLE); return res; } I64 CharScan() {//Checks for MESSAGE_KEY_DOWN and returns 0 immediately if no key. //Waits for MESSAGE_KEY_UP of non-zero ASCII key and returns ASCII if key. //MessageScan() throws away other message types. I64 arg1a, arg2a, arg1b, arg2b; if (!MessageScan(&arg1a, &arg2a, 1 << MESSAGE_KEY_DOWN) || !arg1a) return 0; else do MessageGet(&arg1b, &arg2b, 1 << MESSAGE_KEY_UP); while (!arg1b); //Be careful of SC_SHIFT and SC_CTRL, etc. return arg1a; } Bool KeyScan(I64 *_ch=NULL, I64 *_scan_code=NULL, Bool echo=FALSE) {//Checks for MESSAGE_KEY_DOWN and returns FALSE immediately if no key. //Sets ASCII and scan_code. //Removes key message and returns TRUE. //MessageScan() throws away other message types. I64 ch = 0, sc = 0; if (MessageScan(&ch, &sc, 1 << MESSAGE_KEY_DOWN)) { if (_ch) *_ch = ch; if (_scan_code) *_scan_code = sc; if (echo) PutKey(ch, sc); return TRUE; } else { if (_ch) *_ch = 0; if (_scan_code) *_scan_code = 0; return FALSE; } } I64 KeyGet(I64 *_scan_code=NULL, Bool echo=FALSE, Bool raw_cursor=FALSE) {//Waits for MESSAGE_KEY_DOWN message and returns ASCII. //Sets scan_code. //KeyScan() throws away other message types. I64 ch, sc; Bool cursor_on = FALSE; while (!KeyScan(&ch, &sc, FALSE)) { if (IsRaw && raw_cursor) { if (!cursor_on && ToI64(TSCGet * 5 / counts.time_stamp_freq) & 1) { '.'; cursor_on = TRUE; } else if (cursor_on && !(ToI64(TSCGet * 5 / counts.time_stamp_freq) & 1)) { '' CH_BACKSPACE; cursor_on = FALSE; } } LBts(&Fs->task_flags, TASKf_IDLE); if (IsDebugMode) { //We don't want interrupt-driven keyboard when in debugger //because that could have side-effects or crash, so we poll //keyboard when in debugger with interrupts off. PUSHFD CLI KbdMouseHandler(TRUE, FALSE); KbdMessagesQueue; POPFD } else { LBts(&Fs->task_flags, TASKf_AWAITING_MESSAGE); Yield; } LBtr(&Fs->task_flags, TASKf_IDLE); } if (IsRaw && raw_cursor && cursor_on) '' CH_BACKSPACE; if (echo) PutKey(ch, sc); if (_scan_code) *_scan_code = sc; return ch; } I64 CharGet(I64 *_scan_code=NULL, Bool echo=TRUE, Bool raw_cursor=FALSE) {//Waits for non-zero ASCII key. //Sets scan_code. I64 ch1; do ch1 = KeyGet(_scan_code, FALSE, raw_cursor); while (!ch1); if (echo) { if (!IsRaw) "$PT$%c$FG$", ch1; else "%c", ch1; } return ch1; } U8 *StrGet(U8 *message=NULL, U8 *default=NULL, I64 flags=NONE) {//Returns a MAlloc()ed prompted string. See Flags. U8 *st; if (message) "" message, default; st = (*fp_getstr2)(flags); if (!*st) { Free(st); if (default) return StrNew(default); else return StrNew(""); } return st; } I64 StrNGet(U8 *buf, I64 size, Bool allow_ext=TRUE) {//Prompt into fixed length string. Size must include terminator. U8 *st; I64 ch, i = 0; if (!size || !buf) return 0; if (allow_ext) { st = StrGet; if (StrLen(st) > size - 1) { MemCopy(buf, st, size - 1); buf[size - 1] = 0; } else StrCopy(buf, st); i = StrLen(buf); Free(st); } else { while (TRUE) { ch = CharGet(, FALSE, IsDebugMode); if (ch == '\n') { '' ch; break; } else if (ch == CH_BACKSPACE) { if (i > 0) { i--; '' ch; } } else { if (i < size - 1) { buf[i++] = ch; '' ch; } } } buf[i] = 0; } return i; }