* 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:
@@ -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 ;
|
||||
|
||||
@@ -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,28 +16,26 @@
|
||||
#include <termios.h>
|
||||
#include <unistd.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
|
||||
|
||||
#ifdef USE_INPUT_SERVER
|
||||
# include <Message.h>
|
||||
# include <AppDefs.h>
|
||||
#include <image.h>
|
||||
#include <InterfaceDefs.h>
|
||||
# include <TypeConstants.h>
|
||||
#include <OS.h>
|
||||
|
||||
# include "VTkeymap.h"
|
||||
#endif
|
||||
#include <kb_mouse_driver.h>
|
||||
|
||||
#include "ATKeymap.h"
|
||||
#include "SystemKeymap.h"
|
||||
#include "Keymap.h"
|
||||
|
||||
|
||||
struct console {
|
||||
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;
|
||||
};
|
||||
@@ -49,99 +44,134 @@ struct console {
|
||||
struct console gConsole;
|
||||
|
||||
|
||||
void
|
||||
error(const char* message, ...)
|
||||
{
|
||||
char buffer[2048];
|
||||
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
|
||||
vsnprintf(buffer, sizeof(buffer), message, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
// put it out on stderr as well as to serial/syslog
|
||||
fputs(buffer, stderr);
|
||||
debug_printf("%s", buffer);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
#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);
|
||||
|
||||
free(arg_v[0]);
|
||||
|
||||
int32 tmpbuf[2] = {cursorSem, appArea};
|
||||
int32 code = 0;
|
||||
send_data(isThread, code, (void *)tmpbuf, sizeof(tmpbuf));
|
||||
|
||||
resume_thread(isThread);
|
||||
setpgid(isThread, 0);
|
||||
|
||||
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;
|
||||
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;
|
||||
char buffer[16];
|
||||
if (ioctl(con->keyboard_fd, KB_READ, &buffer) != 0)
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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))
|
||||
if (keycode == 0)
|
||||
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];
|
||||
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;
|
||||
|
||||
for (;;) {
|
||||
ssize_t length = read(con->keyboard_fd, buffer, sizeof(buffer));
|
||||
if (length < 0)
|
||||
break;
|
||||
if ((isKeyDown && !isLock)
|
||||
|| (isKeyDown && !(modifiers & changedModifiers)))
|
||||
modifiers |= changedModifiers;
|
||||
else {
|
||||
modifiers &= ~changedModifiers;
|
||||
|
||||
write(con->tty_master_fd, buffer, length);
|
||||
// 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;
|
||||
}
|
||||
@@ -150,28 +180,75 @@ keyboard_reader(void *arg)
|
||||
static int32
|
||||
console_writer(void* arg)
|
||||
{
|
||||
char buf[1024];
|
||||
ssize_t len;
|
||||
ssize_t write_len;
|
||||
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)
|
||||
{
|
||||
DIR *dir;
|
||||
|
||||
memset(con, 0, sizeof(struct console));
|
||||
con->console_fd = -1;
|
||||
con->keyboard_fd = -1;
|
||||
@@ -184,13 +261,11 @@ 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;
|
||||
char name[64];
|
||||
@@ -199,15 +274,16 @@ start_console(struct console *con)
|
||||
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;
|
||||
@@ -285,28 +354,25 @@ stop_console(struct console* con)
|
||||
static pid_t
|
||||
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;
|
||||
}
|
||||
@@ -315,14 +381,12 @@ start_process(int argc, const char **argv, struct console *con)
|
||||
int
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -343,13 +407,10 @@ main(int argc, char **argv)
|
||||
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 (;;) {
|
||||
|
||||
Reference in New Issue
Block a user