* consoled no longer talks to its own keyboard driver, but uses the new debugger

feature of the usual keyboard drivers (it currently only uses the first one
  always, though, instead of all of them).
* Also, it now loads your current keymap from disk, so you don't need to adapt
  to a different keymap anymore. However, right now, it does not have a built-in
  keymap, so this won't work if there is no Key_map file. This will be done 
  later with some more cleanup.
* It now prints error messages to the syslog/serial as well over debug_printf().
* Removed the BeOS R5 input server mode support.
* Some more cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36260 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-04-14 12:56:57 +00:00
parent 64e57f07ce
commit 467ce4205b
2 changed files with 250 additions and 170 deletions
+20 -1
View File
@@ -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 ] : <src!servers!input>SystemKeymap.h ;
+230 -169
View File
@@ -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 <image.h>
#include <OS.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
@@ -19,159 +16,239 @@
#include <termios.h>
#include <unistd.h>
#include <image.h>
#include <InterfaceDefs.h>
#include <OS.h>
//#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 <kb_mouse_driver.h>
#ifdef USE_INPUT_SERVER
# include <Message.h>
# include <AppDefs.h>
# include <InterfaceDefs.h>
# include <TypeConstants.h>
# 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");
}
}