diff --git a/src/tests/system/consoled/Jamfile b/src/tests/system/consoled/Jamfile index d05a55670e..86a0b4c738 100644 --- a/src/tests/system/consoled/Jamfile +++ b/src/tests/system/consoled/Jamfile @@ -1,6 +1,25 @@ SubDir HAIKU_TOP src tests system consoled ; +UsePrivateHeaders input ; UsePrivateHeaders kernel ; UseHeaders [ FDirName $(HAIKU_TOP) src apps terminal ] ; +UseHeaders [ FDirName $(HAIKU_COMMON_DEBUG_OBJECT_DIR) servers input ] ; -Application consoled : consoled.cpp : $(TARGET_LIBSUPC++) ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons input_server devices + keyboard ] ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers input ] ; + +{ + local defines = [ FDefines CONSOLED ] ; + SubDirCcFlags $(defines) -Wall -Wno-multichar ; + SubDirC++Flags $(defines) -Wall -Wno-multichar ; +} + +Application consoled : + consoled.cpp + + Keymap.cpp + : $(TARGET_LIBSUPC++) +; + +Includes [ FGristFiles consoled.cpp ] : SystemKeymap.h ; diff --git a/src/tests/system/consoled/consoled.cpp b/src/tests/system/consoled/consoled.cpp index 238f00c8b3..7f8d83b7c6 100644 --- a/src/tests/system/consoled/consoled.cpp +++ b/src/tests/system/consoled/consoled.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007, Haiku. All rights reserved. + * Copyright 2004-2010, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2002, Travis Geiselbrecht. All rights reserved. @@ -7,9 +7,6 @@ */ -#include -#include - #include #include #include @@ -19,159 +16,239 @@ #include #include +#include +#include +#include -//#define USE_INPUT_SERVER - // define this if consoled should use the input_server to - // get to its keyboard input - // be sure to define USE_R5_STYLE_COMM in InputServer.h when USE_INPUT_SERVER is defined +#include -#ifdef USE_INPUT_SERVER -# include -# include -# include -# include - -# include "VTkeymap.h" -#endif +#include "ATKeymap.h" +#include "SystemKeymap.h" +#include "Keymap.h" struct console { - int console_fd; - int keyboard_fd; - int tty_master_fd; - int tty_slave_fd; - int tty_num; - thread_id keyboard_reader; - thread_id console_writer; + int console_fd; + int keyboard_fd; + bool is_at; + + int tty_master_fd; + int tty_slave_fd; + int tty_num; + + thread_id keyboard_reader; + thread_id console_writer; }; struct console gConsole; -static int32 -keyboard_reader(void *arg) +void +error(const char* message, ...) { - struct console *con = (struct console *)arg; + char buffer[2048]; -#ifdef USE_INPUT_SERVER - area_id appArea; - void *cursorAddr; - sem_id cursorSem = 0; // not initialized? - thread_id isThread; - port_id isAsPort; - port_id isPort; - - appArea = create_area("isCursor", &cursorAddr, B_ANY_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, B_READ_AREA); - - int32 arg_c = 1; - char **arg_v = (char **)malloc(sizeof(char *) * (arg_c + 1)); - arg_v[0] = strdup("/system/servers/input_server"); - arg_v[1] = NULL; - isThread = load_image(arg_c, (const char**)arg_v, (const char **)environ); + va_list args; + va_start(args, message); - free(arg_v[0]); + vsnprintf(buffer, sizeof(buffer), message, args); - int32 tmpbuf[2] = {cursorSem, appArea}; - int32 code = 0; - send_data(isThread, code, (void *)tmpbuf, sizeof(tmpbuf)); + va_end(args); - resume_thread(isThread); - setpgid(isThread, 0); + // put it out on stderr as well as to serial/syslog + fputs(buffer, stderr); + debug_printf("%s", buffer); +} - thread_id sender; - code = receive_data(&sender, (void *)tmpbuf, sizeof(tmpbuf)); - isAsPort = tmpbuf[0]; - isPort = tmpbuf[1]; - - ssize_t length; - status_t err; - const char *string; + +void +update_leds(int fd, uint32 modifiers) +{ + char lockIO[3] = {0, 0, 0}; + + if ((modifiers & B_NUM_LOCK) != 0) + lockIO[0] = 1; + if ((modifiers & B_CAPS_LOCK) != 0) + lockIO[1] = 1; + if ((modifiers & B_SCROLL_LOCK) != 0) + lockIO[2] = 1; + + ioctl(fd, KB_SET_LEDS, &lockIO); +} + + +static int32 +keyboard_reader(void* arg) +{ + struct console* con = (struct console*)arg; + uint8 activeDeadKey = 0; + uint32 modifiers = 0; + + Keymap keymap; + keymap.LoadCurrent(); for (;;) { - length = port_buffer_size(isAsPort); - char buffer[length]; - err = read_port(isAsPort, &code, buffer, length); - if(err != length) { - if (err > 0) - fprintf(stderr, "consoled: failed to read full packet (read %lu of %lu)\n", err, length); - else - fprintf(stderr, "consoled: read_port error: (0x%lx) %s\n", err, strerror(err)); - continue; - } - - BMessage event; - if ((err = event.Unflatten(buffer)) < 0) { - fprintf(stderr, "consoled: Unflatten() error: (0x%lx) %s\n", err, strerror(err)); - continue; - } - - if ((event.what != B_KEY_DOWN) - || (event.FindString("bytes", &string) != B_OK)) - continue; - - length = strlen(string); - if (length == 1) - switch (*string) { - case B_LEFT_ARROW: - write(con->tty_master_fd, LEFT_ARROW_KEY_CODE, sizeof(LEFT_ARROW_KEY_CODE)); - break; - case B_RIGHT_ARROW: - write(con->tty_master_fd, RIGHT_ARROW_KEY_CODE, sizeof(RIGHT_ARROW_KEY_CODE)); - break; - case B_UP_ARROW: - write(con->tty_master_fd, UP_ARROW_KEY_CODE, sizeof(UP_ARROW_KEY_CODE)); - break; - case B_DOWN_ARROW: - write(con->tty_master_fd, DOWN_ARROW_KEY_CODE, sizeof(DOWN_ARROW_KEY_CODE)); - break; - default: - write(con->tty_master_fd, string, length); - } - else - write(con->tty_master_fd, string, length); - } -#else // USE_INPUT_SERVER - char buffer[1024]; - - for (;;) { - ssize_t length = read(con->keyboard_fd, buffer, sizeof(buffer)); - if (length < 0) + char buffer[16]; + if (ioctl(con->keyboard_fd, KB_READ, &buffer) != 0) break; - write(con->tty_master_fd, buffer, length); + uint32 keycode = 0; + bool isKeyDown = false; + bigtime_t timestamp = 0; + + if (con->is_at) { + at_kbd_io* atKeyboard = (at_kbd_io*)buffer; + if (atKeyboard->scancode > 0) + keycode = kATKeycodeMap[atKeyboard->scancode - 1]; + isKeyDown = atKeyboard->is_keydown; + timestamp = atKeyboard->timestamp; + } else { + raw_key_info* rawKeyInfo= (raw_key_info*)buffer; + isKeyDown = rawKeyInfo->is_keydown; + timestamp = rawKeyInfo->timestamp; + keycode = rawKeyInfo->be_keycode; + } + + if (keycode == 0) + continue; + + uint32 changedModifiers = keymap.Modifier(keycode); + bool isLock = (changedModifiers + & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)) != 0; + if (changedModifiers != 0 && (!isLock || isKeyDown)) { + uint32 oldModifiers = modifiers; + + if ((isKeyDown && !isLock) + || (isKeyDown && !(modifiers & changedModifiers))) + modifiers |= changedModifiers; + else { + modifiers &= ~changedModifiers; + + // ensure that we don't clear a combined B_*_KEY when still + // one of the individual B_{LEFT|RIGHT}_*_KEY is pressed + if (modifiers & (B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY)) + modifiers |= B_SHIFT_KEY; + if (modifiers & (B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY)) + modifiers |= B_COMMAND_KEY; + if (modifiers & (B_LEFT_CONTROL_KEY | B_RIGHT_CONTROL_KEY)) + modifiers |= B_CONTROL_KEY; + if (modifiers & (B_LEFT_OPTION_KEY | B_RIGHT_OPTION_KEY)) + modifiers |= B_OPTION_KEY; + } + + if (modifiers != oldModifiers) { + if (isLock) + update_leds(con->keyboard_fd, modifiers); + } + } + + uint8 newDeadKey = 0; + if (activeDeadKey == 0 || !isKeyDown) + newDeadKey = keymap.IsDeadKey(keycode, modifiers); + + char* string = NULL; + int32 numBytes = 0; + if (newDeadKey == 0 && isKeyDown) { + keymap.GetChars(keycode, modifiers, activeDeadKey, &string, + &numBytes); + if (numBytes > 0) + write(con->tty_master_fd, string, numBytes); + + delete[] string; + } + + if (newDeadKey == 0) { + if (isKeyDown && !modifiers && activeDeadKey != 0) { + // a dead key was completed + activeDeadKey = 0; + } + } else if (isKeyDown) { + // start of a dead key + char* string = NULL; + int32 numBytes = 0; + keymap.GetChars(keycode, modifiers, 0, &string, &numBytes); + + activeDeadKey = newDeadKey; + } } -#endif // USE_INPUT_SERVER return 0; } static int32 -console_writer(void *arg) +console_writer(void* arg) { - char buf[1024]; - ssize_t len; - ssize_t write_len; - struct console *con = (struct console *)arg; + struct console* con = (struct console*)arg; for (;;) { - len = read(con->tty_master_fd, buf, sizeof(buf)); - if (len < 0) + char buffer[1024]; + ssize_t length = read(con->tty_master_fd, buffer, sizeof(buffer)); + if (length < 0) break; - write_len = write(con->console_fd, buf, len); + write(con->console_fd, buffer, length); } return 0; } +/*! Opens the first keyboard driver it finds starting from the given + location \a start that supports the debugger extension. + \a isAT determines whether this is an AT keyboard (that returns + different keycodes) or not. +*/ +static int +open_keyboard(const char* start, bool& isAT) +{ + DIR* dir = opendir(start); + if (dir == NULL) + return -1; + + int fd = -1; + + while (true) { + dirent* entry = readdir(dir); + if (entry == NULL) + break; + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + char path[PATH_MAX]; + strlcpy(path, start, sizeof(path)); + strlcat(path, "/", sizeof(path)); + strlcat(path, entry->d_name, sizeof(path)); + + struct stat stat; + if (::stat(path, &stat) != 0) + continue; + + if (S_ISDIR(stat.st_mode)) + return open_keyboard(path, isAT); + + // Try to open it as a device + fd = open(path, O_RDONLY); + if (fd >= 0) { + // Turn on debugger mode + if (ioctl(fd, KB_SET_DEBUG_READER, NULL, 0) == 0) { + isAT = strstr(path, "keyboard/at") != NULL; + break; + } + close(fd); + fd = -1; + } + } + + closedir(dir); + return fd; +} + + static int -start_console(struct console *con) +start_console(struct console* con) { - DIR *dir; - memset(con, 0, sizeof(struct console)); con->console_fd = -1; con->keyboard_fd = -1; @@ -184,30 +261,29 @@ start_console(struct console *con) if (con->console_fd < 0) return -2; -#ifndef USE_INPUT_SERVER - con->keyboard_fd = open("/dev/keyboard", O_RDONLY); + con->keyboard_fd = open_keyboard("/dev/input/keyboard", con->is_at); if (con->keyboard_fd < 0) return -3; -#endif - dir = opendir("/dev/pt"); + DIR* dir = opendir("/dev/pt"); if (dir != NULL) { - struct dirent *entry; + struct dirent* entry; char name[64]; while ((entry = readdir(dir)) != NULL) { if (entry->d_name[0] == '.') continue; - sprintf(name, "/dev/pt/%s", entry->d_name); - + snprintf(name, sizeof(name), "/dev/pt/%s", entry->d_name); + con->tty_master_fd = open(name, O_RDWR); if (con->tty_master_fd >= 0) { - sprintf(name, "/dev/tt/%s", entry->d_name); + snprintf(name, sizeof(name), "/dev/tt/%s", entry->d_name); con->tty_slave_fd = open(name, O_RDWR); if (con->tty_slave_fd < 0) { - fprintf(stderr, "Could not open tty %s: %s!\n", name, strerror(errno)); + error("Could not open tty %s: %s!\n", name, + strerror(errno)); close(con->tty_master_fd); } else { // set default mode @@ -222,9 +298,11 @@ start_console(struct console *con) tcsetattr(con->tty_slave_fd, TCSANOW, &termios); } - if (ioctl(con->console_fd, TIOCGWINSZ, &size, sizeof(struct winsize)) == 0) { + if (ioctl(con->console_fd, TIOCGWINSZ, &size, + sizeof(struct winsize)) == 0) { // we got the window size from the console - ioctl(con->tty_slave_fd, TIOCSWINSZ, &size, sizeof(struct winsize)); + ioctl(con->tty_slave_fd, TIOCSWINSZ, &size, + sizeof(struct winsize)); } } break; @@ -237,25 +315,19 @@ start_console(struct console *con) if (con->tty_master_fd < 0 || con->tty_slave_fd < 0) return -4; - con->keyboard_reader = spawn_thread(&keyboard_reader, "console reader", B_URGENT_DISPLAY_PRIORITY, con); + con->keyboard_reader = spawn_thread(&keyboard_reader, "console reader", + B_URGENT_DISPLAY_PRIORITY, con); if (con->keyboard_reader < 0) return -7; - con->console_writer = spawn_thread(&console_writer, "console writer", B_URGENT_DISPLAY_PRIORITY, con); + con->console_writer = spawn_thread(&console_writer, "console writer", + B_URGENT_DISPLAY_PRIORITY, con); if (con->console_writer < 0) return -8; resume_thread(con->keyboard_reader); resume_thread(con->console_writer); - setenv("TERM", "beterm", true); - -#ifdef USE_INPUT_SERVER - // wait for the input_server loop so that keyboard input is available - while (find_thread("_input_server_event_loop_") == NULL) { - snooze(100000); - // a tenth of a second - } -#endif + setenv("TERM", "xterm", true); return 0; } @@ -270,10 +342,7 @@ stop_console(struct console* con) // close console and keyboard close(con->console_fd); -#ifndef USE_INPUT_SERVER close(con->keyboard_fd); - // TODO: USE_INPUT_SERVER case. -#endif // wait for the threads status_t returnCode; @@ -283,46 +352,41 @@ stop_console(struct console* con) static pid_t -start_process(int argc, const char **argv, struct console *con) +start_process(int argc, const char** argv, struct console* con) { - int saved_stdin, saved_stdout, saved_stderr; - pid_t pid; - - saved_stdin = dup(0); - saved_stdout = dup(1); - saved_stderr = dup(2); + int savedInput = dup(0); + int savedOutput = dup(1); + int savedError = dup(2); dup2(con->tty_slave_fd, 0); dup2(con->tty_slave_fd, 1); dup2(con->tty_slave_fd, 2); - pid = load_image(argc, argv, (const char **)environ); + pid_t pid = load_image(argc, argv, (const char**)environ); resume_thread(pid); setpgid(pid, 0); tcsetpgrp(con->tty_slave_fd, pid); - dup2(saved_stdin, 0); - dup2(saved_stdout, 1); - dup2(saved_stderr, 2); - close(saved_stdin); - close(saved_stdout); - close(saved_stderr); + dup2(savedInput, 0); + dup2(savedOutput, 1); + dup2(savedError, 2); + close(savedInput); + close(savedOutput); + close(savedError); return pid; } int -main(int argc, char **argv) +main(int argc, char** argv) { - int err; - // we're a session leader setsid(); - err = start_console(&gConsole); + int err = start_console(&gConsole); if (err < 0) { - printf("consoled: error %d starting console\n", err); + error("consoled: error %d starting console.\n", err); return err; } @@ -336,31 +400,28 @@ main(int argc, char **argv) // get the command argument vector int commandArgc = argc - 1; - const char **commandArgv = new const char*[commandArgc + 1]; + const char** commandArgv = new const char*[commandArgc + 1]; for (int i = 0; i < commandArgc; i++) commandArgv[i] = argv[i + 1]; commandArgv[commandArgc] = NULL; // start the process - pid_t process; + pid_t process = start_process(commandArgc, commandArgv, &gConsole); + status_t returnCode; - - process = start_process(commandArgc, commandArgv, &gConsole); - wait_for_thread(process, &returnCode); - } else { // no command given: start a shell in an endless loop for (;;) { pid_t shellProcess; status_t returnCode; - const char *shellArgv[] = { "/bin/sh", "--login", NULL }; + const char* shellArgv[] = { "/bin/sh", "--login", NULL }; shellProcess = start_process(2, shellArgv, &gConsole); - + wait_for_thread(shellProcess, &returnCode); - + puts("Restart shell"); } }