static const char *do_hidden_menu(void) { int key; int timeout_left, this_timeout; clear_screen(); if (!setjmp(timeout_jump)) { timeout_left = cm->timeout; while (!cm->timeout || timeout_left) { int tol = timeout_left / CLK_TCK; print_timeout_message(tol, HIDDEN_ROW, cm->messages[MSG_AUTOBOOT]); this_timeout = min(timeout_left, CLK_TCK); key = mygetkey(this_timeout); if (key != KEY_NONE) return NULL; /* Key pressed */ timeout_left -= this_timeout; } } /* Clear the message from the screen */ print_timeout_message(0, HIDDEN_ROW, ""); if (cm->ontimeout) return cm->ontimeout; else return cm->menu_entries[cm->defentry]->cmdline; /* Default entry */ }
static const char *run_menu(void) { int key; int done = 0; volatile int entry = cm->curentry; int prev_entry = -1; volatile int top = cm->curtop; int prev_top = -1; int clear = 1, to_clear; const char *cmdline = NULL; volatile clock_t key_timeout, timeout_left, this_timeout; const struct menu_entry *me; bool hotkey = false; /* Note: for both key_timeout and timeout == 0 means no limit */ timeout_left = key_timeout = cm->timeout; /* If we're in shiftkey mode, exit immediately unless a shift key is pressed */ if (shiftkey && !shift_is_held()) { return cm->menu_entries[cm->defentry]->cmdline; } else { shiftkey = 0; } /* Do this before hiddenmenu handling, so we show the background */ prepare_screen_for_menu(); /* Handle hiddenmenu */ if (hiddenmenu) { cmdline = do_hidden_menu(); if (cmdline) return cmdline; /* Otherwise display the menu now; the timeout has already been cancelled, since the user pressed a key. */ hiddenmenu = 0; key_timeout = 0; } /* Handle both local and global timeout */ if (setjmp(timeout_jump)) { entry = cm->defentry; if (top < 0 || top < entry - MENU_ROWS + 1) top = max(0, entry - MENU_ROWS + 1); else if (top > entry || top > max(0, cm->nentries - MENU_ROWS)) top = min(entry, max(0, cm->nentries - MENU_ROWS)); draw_menu(cm->ontimeout ? -1 : entry, top, 1); cmdline = cm->ontimeout ? cm->ontimeout : cm->menu_entries[entry]->cmdline; done = 1; } while (!done) { if (entry <= 0) { entry = 0; while (entry < cm->nentries && is_disabled(cm->menu_entries[entry])) entry++; } if (entry >= cm->nentries - 1) { entry = cm->nentries - 1; while (entry > 0 && is_disabled(cm->menu_entries[entry])) entry--; } me = cm->menu_entries[entry]; if (top < 0 || top < entry - MENU_ROWS + 1) top = max(0, entry - MENU_ROWS + 1); else if (top > entry || top > max(0, cm->nentries - MENU_ROWS)) top = min(entry, max(0, cm->nentries - MENU_ROWS)); /* Start with a clear screen */ if (clear) { /* Clear and redraw whole screen */ /* Enable ASCII on G0 and DEC VT on G1; do it in this order to avoid confusing the Linux console */ if (clear >= 2) prepare_screen_for_menu(); clear_screen(); clear = 0; prev_entry = prev_top = -1; } if (top != prev_top) { draw_menu(entry, top, 1); display_help(me->helptext); } else if (entry != prev_entry) { draw_row(prev_entry - top + 4 + VSHIFT, entry, top, 0, 0); draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0); display_help(me->helptext); } prev_entry = entry; prev_top = top; cm->curentry = entry; cm->curtop = top; /* Cursor movement cancels timeout */ if (entry != cm->defentry) key_timeout = 0; if (key_timeout) { int tol = timeout_left / CLK_TCK; print_timeout_message(tol, TIMEOUT_ROW, cm->messages[MSG_AUTOBOOT]); to_clear = 1; } else { to_clear = 0; } if (hotkey && me->immediate) { /* If the hotkey was flagged immediate, simulate pressing ENTER */ key = KEY_ENTER; } else { this_timeout = min(min(key_timeout, timeout_left), (clock_t) CLK_TCK); key = mygetkey(this_timeout); if (key != KEY_NONE) { timeout_left = key_timeout; if (to_clear) printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW); } } hotkey = false; switch (key) { case KEY_NONE: /* Timeout */ /* This is somewhat hacky, but this at least lets the user know what's going on, and still deals with "phantom inputs" e.g. on serial ports. Warning: a timeout will boot the default entry without any password! */ if (key_timeout) { if (timeout_left <= this_timeout) longjmp(timeout_jump, 1); timeout_left -= this_timeout; } break; case KEY_CTRL('L'): clear = 1; break; case KEY_ENTER: case KEY_CTRL('J'): key_timeout = 0; /* Cancels timeout */ if (me->passwd) { clear = 1; done = ask_passwd(me->passwd); } else { done = 1; } cmdline = NULL; if (done) { switch (me->action) { case MA_CMD: cmdline = me->cmdline; break; case MA_SUBMENU: case MA_GOTO: case MA_EXIT: done = 0; clear = 2; cm = me->submenu; entry = cm->curentry; top = cm->curtop; break; case MA_QUIT: /* Quit menu system */ done = 1; clear = 1; draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0); break; case MA_HELP: key = show_message_file(me->cmdline, me->background); /* If the exit was an F-key, display that help screen */ show_fkey(key); done = 0; clear = 1; break; default: done = 0; break; } } if (done && !me->passwd) { /* Only save a new default if we don't have a password... */ if (me->save && me->label) { syslinux_setadv(ADV_MENUSAVE, strlen(me->label), me->label); syslinux_adv_write(); } } break; case KEY_UP: case KEY_CTRL('P'): while (entry > 0) { entry--; if (entry < top) top -= MENU_ROWS; if (!is_disabled(cm->menu_entries[entry])) break; } break; case KEY_DOWN: case KEY_CTRL('N'): while (entry < cm->nentries - 1) { entry++; if (entry >= top + MENU_ROWS) top += MENU_ROWS; if (!is_disabled(cm->menu_entries[entry])) break; } break; case KEY_PGUP: case KEY_LEFT: case KEY_CTRL('B'): case '<': entry -= MENU_ROWS; top -= MENU_ROWS; while (entry > 0 && is_disabled(cm->menu_entries[entry])) { entry--; if (entry < top) top -= MENU_ROWS; } break; case KEY_PGDN: case KEY_RIGHT: case KEY_CTRL('F'): case '>': case ' ': entry += MENU_ROWS; top += MENU_ROWS; while (entry < cm->nentries - 1 && is_disabled(cm->menu_entries[entry])) { entry++; if (entry >= top + MENU_ROWS) top += MENU_ROWS; } break; case '-': while (entry > 0) { entry--; top--; if (!is_disabled(cm->menu_entries[entry])) break; } break; case '+': while (entry < cm->nentries - 1) { entry++; top++; if (!is_disabled(cm->menu_entries[entry])) break; } break; case KEY_CTRL('A'): case KEY_HOME: top = entry = 0; break; case KEY_CTRL('E'): case KEY_END: entry = cm->nentries - 1; top = max(0, cm->nentries - MENU_ROWS); break; case KEY_F1: case KEY_F2: case KEY_F3: case KEY_F4: case KEY_F5: case KEY_F6: case KEY_F7: case KEY_F8: case KEY_F9: case KEY_F10: case KEY_F11: case KEY_F12: show_fkey(key); clear = 1; break; case KEY_TAB: if (cm->allowedit && me->action == MA_CMD) { int ok = 1; key_timeout = 0; /* Cancels timeout */ draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0); if (cm->menu_master_passwd) { ok = ask_passwd(NULL); clear_screen(); draw_menu(-1, top, 0); } else { /* Erase [Tab] message and help text */ printf("\033[%d;1H\1#0\033[K", TABMSG_ROW); display_help(NULL); } if (ok) { cmdline = edit_cmdline(me->cmdline, top); done = !!cmdline; clear = 1; /* In case we hit [Esc] and done is null */ } else { draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0); } } break; case KEY_CTRL('C'): /* Ctrl-C */ case KEY_ESC: /* Esc */ if (cm->parent) { cm = cm->parent; clear = 2; entry = cm->curentry; top = cm->curtop; } else if (cm->allowedit) { done = 1; clear = 1; key_timeout = 0; draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0); if (cm->menu_master_passwd) done = ask_passwd(NULL); } break; default: if (key > 0 && key < 0xFF) { key &= ~0x20; /* Upper case */ if (cm->menu_hotkeys[key]) { key_timeout = 0; entry = cm->menu_hotkeys[key]->entry; /* Should we commit at this point? */ hotkey = true; } } break; } } printf("\033[?25h"); /* Show cursor */ /* Return the label name so localboot and ipappend work */ return cmdline; }