Add keyboard layout support to kernel.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-04-22 14:02:04 +02:00
parent 98ed222c8e
commit f60b2c6ec4
11 changed files with 338 additions and 84 deletions

2
kernel/.gitignore vendored
View File

@ -6,3 +6,5 @@
*.a
*.initrd
*.out
kb/default-kblayout
kb/default-kblayout.h

View File

@ -108,6 +108,7 @@ interlock.o \
interrupt.o \
ioctx.o \
io.o \
kb/kblayout.o \
kb/layout/us.o \
kb/ps2.o \
kernelinfo.o \
@ -193,6 +194,14 @@ sortix.bin: $(ALLOBJS)
endif
%: %.kblayout
kblayout-compiler --format=sortix-kblayout-1 --compression=none $< -o $@
kb/default-kblayout.h: kb/default-kblayout
carray -cgis --uint8_t --guard=SORTIX_KB_DEFAULT_KBLAYOUT_H --identifier=default_kblayout $< -o $@
*.cpp */*.cpp */*/*.cpp: | kb/default-kblayout.h
%.o: %.cpp
$(CXX) -c $< -o $@ $(CPPFLAGS) $(CXXFLAGS)
@ -203,6 +212,7 @@ clean:
rm -f $(ALLOBJS) sortix.bin
rm -f *.bin *.out *.tmp
rm -f *.o */*.o */*/*.o
rm -f kb/default-kblayout kb/default-kblayout.h
# Installation into sysroot
install: install-headers install-kernel

View File

@ -52,14 +52,6 @@ public:
};
class KeyboardLayout
{
public:
virtual ~KeyboardLayout() { }
virtual uint32_t Translate(int kbkey) = 0;
};
} // namespace Sortix
#endif

View File

@ -0,0 +1 @@
../../kblayout/us.kblayout

163
kernel/kb/kblayout.cpp Normal file
View File

@ -0,0 +1,163 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
kb/kblayout.cpp
Engine that executes a keyboard layout program.
*******************************************************************************/
#include <assert.h>
#include <endian.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sortix/kblayout.h>
#include <sortix/kernel/log.h>
#include "kblayout.h"
namespace Sortix {
KeyboardLayoutExecutor::KeyboardLayoutExecutor()
{
memset(&header, 0, sizeof(header));
memset(&modifier_counts, 0, sizeof(modifier_counts));
loaded = false;
actions = NULL;
keys_down = NULL;
modifiers = 0;
saved_data = 0;
saved_data_size = 0;
}
KeyboardLayoutExecutor::~KeyboardLayoutExecutor()
{
delete[] actions;
delete[] keys_down;
delete[] saved_data;
}
bool KeyboardLayoutExecutor::Upload(const uint8_t* input_data, size_t input_size)
{
size_t data_size = input_size;
uint8_t* data = new uint8_t[data_size];
if ( !data )
return false;
memcpy(data, input_data, data_size);
struct kblayout new_header;
if ( data_size < sizeof(struct kblayout) )
return delete[] data, errno = EINVAL, false;
memcpy(&new_header, data, sizeof(new_header));
if ( strncmp(new_header.magic, "sortix-kblayout-1", sizeof(new_header.magic)) != 0 )
return delete[] data, errno = EINVAL, false;
new_header.num_modifiers = le32toh(new_header.num_modifiers);
new_header.num_scancodes = le32toh(new_header.num_scancodes);
if ( KBLAYOUT_MAX_NUM_MODIFIERS <= new_header.num_modifiers )
return errno = EINVAL, false;
// TODO: Limit num_scancodes and max_actions.
size_t remaining_size = data_size - sizeof(new_header);
// TODO: Check for overflow.
size_t table_length = (size_t) (1 << new_header.num_modifiers) *
(size_t) new_header.num_scancodes;
size_t table_size = sizeof(struct kblayout_action) * table_length;
if ( remaining_size < table_size )
return delete[] data, errno = EINVAL, false;
struct kblayout_action* new_actions = new struct kblayout_action[table_length];
if ( !new_actions )
return delete[] data, false;
uint8_t* new_keys_down = new uint8_t[new_header.num_scancodes];
if ( !new_keys_down )
return delete[] data, delete[] new_actions, false;
memcpy(new_actions, data + sizeof(new_header), table_size);
for ( size_t i = 0; i < table_length; i++ )
new_actions[i] = le32toh(new_actions[i]);
memcpy(&header, &new_header, sizeof(header));
delete[] actions;
actions = new_actions;
memset(new_keys_down, 0, sizeof(keys_down[0]) * new_header.num_scancodes);
delete[] keys_down;
keys_down = new_keys_down;
memset(&modifier_counts, 0, sizeof(modifier_counts));
modifiers = 0;
delete[] saved_data;
saved_data = data;
saved_data_size = data_size;
loaded = true;
return true;
}
bool KeyboardLayoutExecutor::Download(const uint8_t** data, size_t* data_size)
{
if ( !saved_data )
return errno = EINIT, false;
return *data = saved_data, *data_size = saved_data_size, true;
}
uint32_t KeyboardLayoutExecutor::Translate(int kbkey)
{
if ( !loaded )
return 0;
unsigned int abskbkey = kbkey < 0 ? - (unsigned int) kbkey : kbkey;
if ( header.num_scancodes <= abskbkey )
return 0;
bool repeated_key = 0 <= kbkey && keys_down[abskbkey];
keys_down[abskbkey] = 0 <= kbkey ? 1 : 0;
size_t action_index = abskbkey * (1 << header.num_modifiers) + modifiers;
struct kblayout_action* action = &actions[action_index];
if ( 0 < kbkey && action->type == KBLAYOUT_ACTION_TYPE_CODEPOINT )
return action->codepoint;
// TODO: Properly implement dead keys!
if ( 0 < kbkey && action->type == KBLAYOUT_ACTION_TYPE_DEAD )
return action->codepoint;
if ( repeated_key )
return 0;
if ( action->type == KBLAYOUT_ACTION_TYPE_MODIFY &&
action->codepoint < header.num_modifiers )
{
if ( kbkey < 0 )
{
if ( --modifier_counts[action->codepoint] == 0 )
modifiers &= ~(1 << action->codepoint);
}
else
{
modifier_counts[action->codepoint]++;
modifiers |= 1 << action->codepoint;
}
return 0;
}
if ( 0 <= kbkey &&
action->type == KBLAYOUT_ACTION_TYPE_TOGGLE &&
action->codepoint < header.num_modifiers )
{
if ( (modifier_counts[action->codepoint] = !modifier_counts[action->codepoint]) )
modifiers |= 1 << action->codepoint;
else
modifiers &= ~(1 << action->codepoint);
return 0;
}
return 0;
}
} // namespace Sortix

60
kernel/kb/kblayout.h Normal file
View File

@ -0,0 +1,60 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2014.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
kb/kblayout.h
Engine that executes a keyboard layout program.
*******************************************************************************/
#ifndef SORTIX_KB_KBLAYOUT_H
#define SORTIX_KB_KBLAYOUT_H
#include <stddef.h>
#include <stdint.h>
#include <sortix/kblayout.h>
namespace Sortix {
class KeyboardLayoutExecutor
{
public:
KeyboardLayoutExecutor();
~KeyboardLayoutExecutor();
public:
bool Upload(const uint8_t* data, size_t data_size);
bool Download(const uint8_t** data, size_t* data_size);
uint32_t Translate(int kbkey);
private:
struct kblayout header;
struct kblayout_action* actions;
uint8_t* keys_down;
uint32_t modifier_counts[KBLAYOUT_MAX_NUM_MODIFIERS];
uint32_t modifiers;
bool loaded;
uint8_t* saved_data;
size_t saved_data_size;
};
} // namespace Sortix
#endif

View File

@ -42,62 +42,62 @@ const uint32_t LAYOUT_US[4UL*128UL] =
{
0, 0, 0, 0, /* unused: kbkey 0 is invalid */
0, 0, 0, 0, /* KBKEY_ESC */
'1', '!', '1', '!',
'2', '@', '2', '@',
'3', '#', '3', '#',
'4', '$', '4', '$',
'5', '%', '5', '%',
'6', '^', '6', '^',
'7', '&', '7', '&',
'8', '*', '8', '*',
'9', '(', '9', '(',
'0', ')', '0', ')',
'-', '_', '-', '_',
'=', '+', '=', '+',
'\b', '\b', '\b', '\b',
'\t', '\t', '\t', '\t',
'q', 'Q', 'Q', 'q',
'w', 'W', 'W', 'w',
'e', 'E', 'E', 'e',
'r', 'R', 'R', 'r',
't', 'T', 'T', 't',
'y', 'Y', 'Y', 'y',
'u', 'U', 'U', 'u',
'i', 'I', 'I', 'i',
'o', 'O', 'O', 'o',
'p', 'P', 'P', 'p',
'[', '{', '[', '{',
']', '}', ']', '}',
'\n', '\n', '\n', '\n',
L'1', L'!', L'1', L'!',
L'2', L'@', L'2', L'@',
L'3', L'#', L'3', L'#',
L'4', L'$', L'4', L'$',
L'5', L'%', L'5', L'%',
L'6', L'^', L'6', L'^',
L'7', L'&', L'7', L'&',
L'8', L'*', L'8', L'*',
L'9', L'(', L'9', L'(',
L'0', L')', L'0', L')',
L'-', L'_', L'-', L'_',
L'=', L'+', L'=', L'+',
L'\b', L'\b', L'\b', L'\b',
L'\t', L'\t', L'\t', L'\t',
L'q', L'Q', L'Q', L'q',
L'w', L'W', L'W', L'w',
L'e', L'E', L'E', L'e',
L'r', L'R', L'R', L'r',
L't', L'T', L'T', L't',
L'y', L'Y', L'Y', L'y',
L'u', L'U', L'U', L'u',
L'i', L'I', L'I', L'i',
L'o', L'O', L'O', L'o',
L'p', L'P', L'P', L'p',
L'[', L'{', L'[', L'{',
L']', L'}', L']', L'}',
L'\n', L'\n', L'\n', L'\n',
0, 0, 0, 0, /* KBKEY_LCTRL */
'a', 'A', 'A', 'a',
's', 'S', 'S', 's',
'd', 'D', 'D', 'd',
'f', 'F', 'F', 'f',
'g', 'G', 'G', 'g',
'h', 'H', 'H', 'h',
'j', 'J', 'J', 'j',
'k', 'K', 'K', 'k',
'l', 'L', 'L', 'l',
';', ':', ';', ':',
'\'', '"', '\'', '"',
'`', '~', '`', '~',
L'a', L'A', L'A', L'a',
L's', L'S', L'S', L's',
L'd', L'D', L'D', L'd',
L'f', L'F', L'F', L'f',
L'g', L'G', L'G', L'g',
L'h', L'H', L'H', L'h',
L'j', L'J', L'J', L'j',
L'k', L'K', L'K', L'k',
L'l', L'L', L'L', L'l',
L';', L':', L';', L':',
L'\'', L'"', L'\'', L'"',
L'`', L'~', L'`', L'~',
0, 0, 0, 0, /* KBKEY_LSHIFT */
'\\', '|', '\\', '|',
'z', 'Z', 'Z', 'z',
'x', 'X', 'X', 'x',
'c', 'C', 'C', 'c',
'v', 'V', 'V', 'v',
'b', 'B', 'B', 'b',
'n', 'N', 'N', 'n',
'm', 'M', 'M', 'm',
',', '<', ',', '<',
'.', '>', '.', '>',
'/', '?', '/', '?',
L'\\', L'|', L'\\', L'|',
L'z', L'Z', L'Z', L'z',
L'x', L'X', L'X', L'x',
L'c', L'C', L'C', L'c',
L'v', L'V', L'V', L'v',
L'b', L'B', L'B', L'b',
L'n', L'N', L'N', L'n',
L'm', L'M', L'M', L'm',
L',', L'<', L',', L'<',
L'.', L'>', L'.', L'>',
L'/', L'?', L'/', L'?',
0, 0, 0, 0, /* KBKEY_RSHIFT */
'*', '*', '*', '*',
L'*', L'*', L'*', L'*',
0, 0, 0, 0, /* KBKEY_LALT */
' ', ' ', ' ', ' ',
L' ', L' ', L' ', L' ',
0, 0, 0, 0, /* KBKEY_CAPSLOCK */
0, 0, 0, 0, /* KBKEY_F1 */
0, 0, 0, 0, /* KBKEY_F2 */
@ -114,11 +114,11 @@ const uint32_t LAYOUT_US[4UL*128UL] =
0, 0, 0, 0, /* KBKEY_KPAD7 */
0, 0, 0, 0, /* KBKEY_KPAD8 */
0, 0, 0, 0, /* KBKEY_KPAD9 */
'-', '-', '-', '-',
L'-', L'-', L'-', L'-',
0, 0, 0, 0, /* KBKEY_KPAD4 */
0, 0, 0, 0, /* KBKEY_KPAD5 */
0, 0, 0, 0, /* KBKEY_KPAD6 */
'+', '+', '+', '+',
L'+', L'+', L'+', L'+',
/* Nothing printable after this point */
};

View File

@ -27,18 +27,14 @@
#include <stdint.h>
#include <sortix/kernel/keyboard.h>
namespace Sortix {
class KBLayoutUS : public KeyboardLayout
class KBLayoutUS
{
public:
KBLayoutUS();
virtual ~KBLayoutUS();
virtual uint32_t Translate(int kbkey);
public:
~KBLayoutUS();
uint32_t Translate(int kbkey);
bool ProcessModifier(int kbkey, int modkey, unsigned flag);
private:

View File

@ -81,7 +81,8 @@
#include "fs/zero.h"
#include "gpu/bga/bga.h"
#include "initrd.h"
#include "kb/layout/us.h"
#include "kb/default-kblayout.h"
#include "kb/kblayout.h"
#include "kb/ps2.h"
#include "logterminal.h"
#include "multiboot.h"
@ -554,9 +555,11 @@ static void BootThread(void* /*user*/)
Keyboard* keyboard = new PS2Keyboard(0x60, Interrupt::IRQ1);
if ( !keyboard )
Panic("Could not allocate PS2 Keyboard driver");
KeyboardLayout* kblayout = new KBLayoutUS;
KeyboardLayoutExecutor* kblayout = new KeyboardLayoutExecutor;
if ( !kblayout )
Panic("Could not allocate keyboard layout driver");
Panic("Could not allocate keyboard layout executor");
if ( !kblayout->Upload(default_kblayout, sizeof(default_kblayout)) )
Panic("Could not load the default keyboard layout into the executor");
// Register the kernel terminal as /dev/tty.
Ref<Inode> tty(new LogTerminal(slashdev->dev, 0666, 0, 0, keyboard, kblayout));

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
This file is part of Sortix.
@ -63,7 +63,7 @@ const unsigned SUPPORTED_MODES = TERMMODE_KBKEY
| TERMMODE_NONBLOCK;
LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
Keyboard* keyboard, KeyboardLayout* kblayout)
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout)
{
inode_type = INODE_TYPE_TTY;
this->dev = dev;
@ -448,12 +448,26 @@ ssize_t LogTerminal::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, siz
{
if ( !name )
{
char index[] = "";
if ( buffer && count < sizeof(index) )
static const char index[] = "kblayout\0";
size_t index_size = sizeof(index) - 1;
if ( buffer && count < index_size )
return errno = ERANGE, -1;
if ( buffer && !ctx->copy_to_dest(buffer, &index, sizeof(index)) )
if ( buffer && !ctx->copy_to_dest(buffer, &index, index_size) )
return -1;
return (ssize_t) sizeof(index);
return (ssize_t) index_size;
}
else if ( !strcmp(name, "kblayout") )
{
ScopedLockSignal lock(&termlock);
const uint8_t* data;
size_t size;
if ( !kblayout->Download(&data, &size) )
return -1;
if ( buffer && count < size )
return errno = ERANGE, -1;
if ( buffer && !ctx->copy_to_dest(buffer, data, size) )
return -1;
return (ssize_t) size;
}
else
return errno = ENOENT, -1;
@ -461,11 +475,21 @@ ssize_t LogTerminal::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, siz
ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count)
{
(void) ctx;
(void) buffer;
(void) count;
if ( !name )
return errno = EPERM, -1;
else if ( !strcmp(name, "kblayout") )
{
uint8_t* data = new uint8_t[count];
if ( !data )
return -1;
if ( !ctx->copy_from_src(data, buffer, count) )
return -1;
ScopedLockSignal lock(&termlock);
if ( !kblayout->Upload(data, count) )
return -1;
delete[] data;
return (ssize_t) count;
}
else
return errno = ENOENT, -1;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
This file is part of Sortix.
@ -29,6 +29,9 @@
#include <sortix/kernel/inode.h>
#include <sortix/kernel/keyboard.h>
#include <sortix/kernel/poll.h>
#include "kb/kblayout.h"
#include "linebuffer.h"
namespace Sortix {
@ -37,7 +40,7 @@ class LogTerminal : public AbstractInode, public KeyboardOwner
{
public:
LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
Keyboard* keyboard, KeyboardLayout* kblayout);
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout);
virtual ~LogTerminal();
public:
@ -71,7 +74,7 @@ private:
size_t numwaiting;
size_t numeofs;
Keyboard* keyboard;
KeyboardLayout* kblayout;
KeyboardLayoutExecutor* kblayout;
LineBuffer linebuffer;
size_t partiallywritten;
unsigned termmode;