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 *.a
*.initrd *.initrd
*.out *.out
kb/default-kblayout
kb/default-kblayout.h

View File

@ -108,6 +108,7 @@ interlock.o \
interrupt.o \ interrupt.o \
ioctx.o \ ioctx.o \
io.o \ io.o \
kb/kblayout.o \
kb/layout/us.o \ kb/layout/us.o \
kb/ps2.o \ kb/ps2.o \
kernelinfo.o \ kernelinfo.o \
@ -193,6 +194,14 @@ sortix.bin: $(ALLOBJS)
endif 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 %.o: %.cpp
$(CXX) -c $< -o $@ $(CPPFLAGS) $(CXXFLAGS) $(CXX) -c $< -o $@ $(CPPFLAGS) $(CXXFLAGS)
@ -203,6 +212,7 @@ clean:
rm -f $(ALLOBJS) sortix.bin rm -f $(ALLOBJS) sortix.bin
rm -f *.bin *.out *.tmp rm -f *.bin *.out *.tmp
rm -f *.o */*.o */*/*.o rm -f *.o */*.o */*/*.o
rm -f kb/default-kblayout kb/default-kblayout.h
# Installation into sysroot # Installation into sysroot
install: install-headers install-kernel 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 } // namespace Sortix
#endif #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, /* unused: kbkey 0 is invalid */
0, 0, 0, 0, /* KBKEY_ESC */ 0, 0, 0, 0, /* KBKEY_ESC */
'1', '!', '1', '!', L'1', L'!', L'1', L'!',
'2', '@', '2', '@', L'2', L'@', L'2', L'@',
'3', '#', '3', '#', L'3', L'#', L'3', L'#',
'4', '$', '4', '$', L'4', L'$', L'4', L'$',
'5', '%', '5', '%', L'5', L'%', L'5', L'%',
'6', '^', '6', '^', L'6', L'^', L'6', L'^',
'7', '&', '7', '&', L'7', L'&', L'7', L'&',
'8', '*', '8', '*', L'8', L'*', L'8', L'*',
'9', '(', '9', '(', L'9', L'(', L'9', L'(',
'0', ')', '0', ')', L'0', L')', L'0', L')',
'-', '_', '-', '_', L'-', L'_', L'-', L'_',
'=', '+', '=', '+', L'=', L'+', L'=', L'+',
'\b', '\b', '\b', '\b', L'\b', L'\b', L'\b', L'\b',
'\t', '\t', '\t', '\t', L'\t', L'\t', L'\t', L'\t',
'q', 'Q', 'Q', 'q', L'q', L'Q', L'Q', L'q',
'w', 'W', 'W', 'w', L'w', L'W', L'W', L'w',
'e', 'E', 'E', 'e', L'e', L'E', L'E', L'e',
'r', 'R', 'R', 'r', L'r', L'R', L'R', L'r',
't', 'T', 'T', 't', L't', L'T', L'T', L't',
'y', 'Y', 'Y', 'y', L'y', L'Y', L'Y', L'y',
'u', 'U', 'U', 'u', L'u', L'U', L'U', L'u',
'i', 'I', 'I', 'i', L'i', L'I', L'I', L'i',
'o', 'O', 'O', 'o', L'o', L'O', L'O', L'o',
'p', 'P', 'P', 'p', L'p', L'P', L'P', L'p',
'[', '{', '[', '{', L'[', L'{', L'[', L'{',
']', '}', ']', '}', L']', L'}', L']', L'}',
'\n', '\n', '\n', '\n', L'\n', L'\n', L'\n', L'\n',
0, 0, 0, 0, /* KBKEY_LCTRL */ 0, 0, 0, 0, /* KBKEY_LCTRL */
'a', 'A', 'A', 'a', L'a', L'A', L'A', L'a',
's', 'S', 'S', 's', L's', L'S', L'S', L's',
'd', 'D', 'D', 'd', L'd', L'D', L'D', L'd',
'f', 'F', 'F', 'f', L'f', L'F', L'F', L'f',
'g', 'G', 'G', 'g', L'g', L'G', L'G', L'g',
'h', 'H', 'H', 'h', L'h', L'H', L'H', L'h',
'j', 'J', 'J', 'j', L'j', L'J', L'J', L'j',
'k', 'K', 'K', 'k', 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'"',
'`', '~', '`', '~', L'`', L'~', L'`', L'~',
0, 0, 0, 0, /* KBKEY_LSHIFT */ 0, 0, 0, 0, /* KBKEY_LSHIFT */
'\\', '|', '\\', '|', L'\\', L'|', L'\\', L'|',
'z', 'Z', 'Z', 'z', L'z', L'Z', L'Z', L'z',
'x', 'X', 'X', 'x', L'x', L'X', L'X', L'x',
'c', 'C', 'C', 'c', L'c', L'C', L'C', L'c',
'v', 'V', 'V', 'v', L'v', L'V', L'V', L'v',
'b', 'B', 'B', 'b', L'b', L'B', L'B', L'b',
'n', 'N', 'N', 'n', L'n', L'N', L'N', L'n',
'm', 'M', 'M', 'm', 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 */ 0, 0, 0, 0, /* KBKEY_RSHIFT */
'*', '*', '*', '*', L'*', L'*', L'*', L'*',
0, 0, 0, 0, /* KBKEY_LALT */ 0, 0, 0, 0, /* KBKEY_LALT */
' ', ' ', ' ', ' ', L' ', L' ', L' ', L' ',
0, 0, 0, 0, /* KBKEY_CAPSLOCK */ 0, 0, 0, 0, /* KBKEY_CAPSLOCK */
0, 0, 0, 0, /* KBKEY_F1 */ 0, 0, 0, 0, /* KBKEY_F1 */
0, 0, 0, 0, /* KBKEY_F2 */ 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_KPAD7 */
0, 0, 0, 0, /* KBKEY_KPAD8 */ 0, 0, 0, 0, /* KBKEY_KPAD8 */
0, 0, 0, 0, /* KBKEY_KPAD9 */ 0, 0, 0, 0, /* KBKEY_KPAD9 */
'-', '-', '-', '-', L'-', L'-', L'-', L'-',
0, 0, 0, 0, /* KBKEY_KPAD4 */ 0, 0, 0, 0, /* KBKEY_KPAD4 */
0, 0, 0, 0, /* KBKEY_KPAD5 */ 0, 0, 0, 0, /* KBKEY_KPAD5 */
0, 0, 0, 0, /* KBKEY_KPAD6 */ 0, 0, 0, 0, /* KBKEY_KPAD6 */
'+', '+', '+', '+', L'+', L'+', L'+', L'+',
/* Nothing printable after this point */ /* Nothing printable after this point */
}; };

View File

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

View File

@ -81,7 +81,8 @@
#include "fs/zero.h" #include "fs/zero.h"
#include "gpu/bga/bga.h" #include "gpu/bga/bga.h"
#include "initrd.h" #include "initrd.h"
#include "kb/layout/us.h" #include "kb/default-kblayout.h"
#include "kb/kblayout.h"
#include "kb/ps2.h" #include "kb/ps2.h"
#include "logterminal.h" #include "logterminal.h"
#include "multiboot.h" #include "multiboot.h"
@ -554,9 +555,11 @@ static void BootThread(void* /*user*/)
Keyboard* keyboard = new PS2Keyboard(0x60, Interrupt::IRQ1); Keyboard* keyboard = new PS2Keyboard(0x60, Interrupt::IRQ1);
if ( !keyboard ) if ( !keyboard )
Panic("Could not allocate PS2 Keyboard driver"); Panic("Could not allocate PS2 Keyboard driver");
KeyboardLayout* kblayout = new KBLayoutUS; KeyboardLayoutExecutor* kblayout = new KeyboardLayoutExecutor;
if ( !kblayout ) 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. // Register the kernel terminal as /dev/tty.
Ref<Inode> tty(new LogTerminal(slashdev->dev, 0666, 0, 0, keyboard, kblayout)); 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. This file is part of Sortix.
@ -63,7 +63,7 @@ const unsigned SUPPORTED_MODES = TERMMODE_KBKEY
| TERMMODE_NONBLOCK; | TERMMODE_NONBLOCK;
LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group, 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; inode_type = INODE_TYPE_TTY;
this->dev = dev; this->dev = dev;
@ -448,12 +448,26 @@ ssize_t LogTerminal::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, siz
{ {
if ( !name ) if ( !name )
{ {
char index[] = ""; static const char index[] = "kblayout\0";
if ( buffer && count < sizeof(index) ) size_t index_size = sizeof(index) - 1;
if ( buffer && count < index_size )
return errno = ERANGE, -1; 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 -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 else
return errno = ENOENT, -1; 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) ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count)
{ {
(void) ctx;
(void) buffer;
(void) count;
if ( !name ) if ( !name )
return errno = EPERM, -1; 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 else
return errno = ENOENT, -1; 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. This file is part of Sortix.
@ -29,6 +29,9 @@
#include <sortix/kernel/inode.h> #include <sortix/kernel/inode.h>
#include <sortix/kernel/keyboard.h> #include <sortix/kernel/keyboard.h>
#include <sortix/kernel/poll.h> #include <sortix/kernel/poll.h>
#include "kb/kblayout.h"
#include "linebuffer.h" #include "linebuffer.h"
namespace Sortix { namespace Sortix {
@ -37,7 +40,7 @@ class LogTerminal : public AbstractInode, public KeyboardOwner
{ {
public: public:
LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group, LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
Keyboard* keyboard, KeyboardLayout* kblayout); Keyboard* keyboard, KeyboardLayoutExecutor* kblayout);
virtual ~LogTerminal(); virtual ~LogTerminal();
public: public:
@ -71,7 +74,7 @@ private:
size_t numwaiting; size_t numwaiting;
size_t numeofs; size_t numeofs;
Keyboard* keyboard; Keyboard* keyboard;
KeyboardLayout* kblayout; KeyboardLayoutExecutor* kblayout;
LineBuffer linebuffer; LineBuffer linebuffer;
size_t partiallywritten; size_t partiallywritten;
unsigned termmode; unsigned termmode;