Refactored the kernel keyboard API, but kept system calls compatible.

Caps lock now works as caps lock, not as shift lock.

This new design will allow implementing a working tty, such that stdin is
the only way to access the keyboard, instead of the current hacky way of
using a special system call to read from the keyboard.

Added a new system header file <sys/keycodes.h> defining the constants for
every key on the keyboard. This will be used in future APIs.

The main change is to split the keyboard driver into a class that reads
from the keyboard, while another class handles the translation into
printable characters (if possible). This allows a terminal driver based
on logical key presses and printable characters, instead of a terminal
driver based only on unicode-ish codes.
This commit is contained in:
Jonas 'Sortie' Termansen 2012-01-07 21:09:01 +01:00
parent 16dd39e467
commit ead0e1523f
13 changed files with 909 additions and 711 deletions

View File

@ -50,6 +50,7 @@ c/h/string.h \
c/h/errno.h \
c/h/error.h \
c/h/dirent.h \
c/h/sys/keycodes.h \
c/h/sys/readdirents.h \
c/h/sys/stat.h \
c/h/sys/types.h \

View File

@ -0,0 +1,32 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
This file is part of LibMaxsi.
LibMaxsi is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
LibMaxsi 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 Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with LibMaxsi. If not, see <http://www.gnu.org/licenses/>.
keycodes.h
Defines codes for every logical key on keyboards.
******************************************************************************/
#ifndef _SYS_KEYCODES_H
#define _SYS_KEYCODES_H 1
#include <features.h>
#include <sortix/keycodes.h>
#endif

View File

@ -42,7 +42,7 @@ ifdef X86FAMILY
CPUFLAGS:=$(CPUFLAGS) -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow
endif
DIRS=. x64 x86 x86-family fs
DIRS=. x64 x86 x86-family fs kb kb/layout
DEFINES:=-DSORTIX_KERNEL $(CPUDEFINES)
ifeq ($(JSSORTIX),1)
@ -69,6 +69,9 @@ log.o \
utf8.o \
panic.o \
keyboard.o \
kbapiadapter.o \
kb/ps2.o \
kb/layout/us.o \
scheduler.o \
syscall.o \
sound.o \

153
sortix/kb/layout/us.cpp Normal file
View File

@ -0,0 +1,153 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
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/>.
ks/layout/us.cpp
The United States keyboard layout.
******************************************************************************/
#include "../../platform.h"
#include "../../keyboard.h"
#include "../../keycodes.h"
#include "us.h"
namespace Sortix
{
const unsigned MOD_LSHIFT = (1U<<0U);
const unsigned MOD_CAPS = (1U<<1U);
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',
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',
';', ':', ';', ':',
':', '"', ':', '"',
'`', '~', '`', '~',
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',
',', '<', ',', '<',
'.', '>', '.', '>',
'/', '?', '/', '?',
0, 0, 0, 0, /* KBKEY_RSHIFT */
'*', '*', '*', '*',
0, 0, 0, 0, /* KBKEY_LALT */
' ', ' ', ' ', ' ',
0, 0, 0, 0, /* KBKEY_CAPSLOCK */
0, 0, 0, 0, /* KBKEY_F1 */
0, 0, 0, 0, /* KBKEY_F2 */
0, 0, 0, 0, /* KBKEY_F3 */
0, 0, 0, 0, /* KBKEY_F4 */
0, 0, 0, 0, /* KBKEY_F5 */
0, 0, 0, 0, /* KBKEY_F6 */
0, 0, 0, 0, /* KBKEY_F7 */
0, 0, 0, 0, /* KBKEY_F8 */
0, 0, 0, 0, /* KBKEY_F9 */
0, 0, 0, 0, /* KBKEY_F10 */
0, 0, 0, 0, /* KBKEY_NUMLOCK */
0, 0, 0, 0, /* KBKEY_SCROLLLOCK */
0, 0, 0, 0, /* KBKEY_KPAD7 */
0, 0, 0, 0, /* KBKEY_KPAD8 */
0, 0, 0, 0, /* KBKEY_KPAD9 */
'-', '-', '-', '-',
0, 0, 0, 0, /* KBKEY_KPAD4 */
0, 0, 0, 0, /* KBKEY_KPAD5 */
0, 0, 0, 0, /* KBKEY_KPAD6 */
'+', '+', '+', '+',
/* Nothing printable after this point */
};
KBLayoutUS::KBLayoutUS()
{
modifiers = 0;
}
KBLayoutUS::~KBLayoutUS()
{
}
bool KBLayoutUS::ProcessModifier(int logickey, int modkey, unsigned flag)
{
if ( logickey == modkey ) { modifiers |= flag; return true; }
if ( logickey == -modkey ) { modifiers &= ~flag; return true; }
return false;
}
uint32_t KBLayoutUS::Translate(int kbkey)
{
if ( kbkey == KBKEY_LSHIFT ) { modifiers |= MOD_LSHIFT; return 0; }
if ( kbkey == -KBKEY_LSHIFT ) { modifiers &= ~MOD_LSHIFT; return 0; }
if ( kbkey == KBKEY_CAPSLOCK ) { modifiers ^= MOD_CAPS; return 0; }
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
unsigned usedmods = modifiers & (MOD_LSHIFT | MOD_CAPS);
size_t index = (abskbkey<<2) | usedmods;
// Check if the kbkey is outside the layout structure (not printable).
size_t numchars = sizeof(LAYOUT_US) / 4UL / sizeof(uint32_t);
if ( numchars < abskbkey ) { return 0; }
return LAYOUT_US[index];
}
}

49
sortix/kb/layout/us.h Normal file
View File

@ -0,0 +1,49 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
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/>.
ks/layout/us.h
The United States keyboard layout.
******************************************************************************/
#ifndef SORTIX_KB_LAYOUT_US_H
#define SORTIX_KB_LAYOUT_US_H
#include "../../keyboard.h"
namespace Sortix
{
class KBLayoutUS : public KeyboardLayout
{
public:
KBLayoutUS();
virtual ~KBLayoutUS();
virtual uint32_t Translate(int kbkey);
public:
bool ProcessModifier(int kbkey, int modkey, unsigned flag);
private:
unsigned modifiers;
};
}
#endif

193
sortix/kb/ps2.cpp Normal file
View File

@ -0,0 +1,193 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
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/ps2.cpp
A driver for the PS2 Keyboard.
******************************************************************************/
#include "../platform.h"
#include <libmaxsi/memory.h>
#include "../interrupt.h"
#include "../keyboard.h"
#include "../keycodes.h"
#include "ps2.h"
using namespace Maxsi;
namespace Sortix
{
const uint16_t DATA = 0x0;
const uint16_t COMMAND = 0x0;
const uint16_t STATUS = 0x4;
const uint8_t CMD_SETLED = 0xED;
const uint8_t LED_SCRLCK = (1<<0);
const uint8_t LED_NUMLCK = (1<<1);
const uint8_t LED_CAPSLCK = (1<<2);
void PS2Keyboard__OnInterrupt(CPU::InterruptRegisters* regs, void* user)
{
((PS2Keyboard*) user)->OnInterrupt(regs);
}
PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
{
this->queue = NULL;
this->queuelength = 0;
this->queueoffset = 0;
this->queueused = 0;
this->owner = NULL;
this->ownerptr = NULL;
this->iobase = iobase;
this->interrupt = interrupt;
this->leds = 0;
this->scancodeescaped = false;
Interrupt::RegisterHandler(interrupt, PS2Keyboard__OnInterrupt, this);
// If any scancodes were already pending, our interrupt handler will
// never be called. Let's just discard anything pending.
PopScancode();
}
PS2Keyboard::~PS2Keyboard()
{
Interrupt::RegisterHandler(interrupt, NULL, NULL);
delete[] queue;
}
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* /*regs*/)
{
uint8_t scancode = PopScancode();
int kbkey = DecodeScancode(scancode);
if ( !kbkey ) { return; }
if ( !PushKey(kbkey) )
{
Log::PrintF("Warning: dropping keystroke due to insufficient "
"storage space in PS2 keyboard driver.\n");
return;
}
uint8_t newleds = leds;
if ( kbkey == KBKEY_CAPSLOCK ) { newleds ^= LED_CAPSLCK; }
if ( kbkey == KBKEY_SCROLLLOCK ) { newleds ^= LED_SCRLCK; }
if ( kbkey == KBKEY_NUMLOCK ) { newleds ^= LED_NUMLCK; }
if ( newleds != leds ) { UpdateLEDs(leds = newleds); }
NotifyOwner();
}
void PS2Keyboard::NotifyOwner()
{
if ( !owner) { return; }
owner->OnKeystroke(this, ownerptr);
}
int PS2Keyboard::DecodeScancode(uint8_t scancode)
{
const uint8_t SCANCODE_ESCAPE = 0xE0;
if ( scancode == SCANCODE_ESCAPE )
{
scancodeescaped = true;
return 0;
}
int offset = (scancodeescaped) ? 0x80 : 0;
int kbkey = scancode & 0x7F;
if ( scancode & 0x80 ) { kbkey = -kbkey - offset; }
else { kbkey = kbkey + offset; }
scancodeescaped = false;
// kbkey is now in the format specified in <sortix/keycodes.h>.
return kbkey;
}
uint8_t PS2Keyboard::PopScancode()
{
return CPU::InPortB(iobase + DATA);
}
void PS2Keyboard::UpdateLEDs(int ledval)
{
while ( (CPU::InPortB(iobase + STATUS) & (1<<1)) != 0 ) { }
CPU::OutPortB(iobase + COMMAND, CMD_SETLED);
while ( (CPU::InPortB(iobase + STATUS) & (1<<1)) != 0 ) { }
CPU::OutPortB(iobase + COMMAND, ledval);
}
void PS2Keyboard::SetOwner(KeyboardOwner* owner, void* user)
{
this->owner = owner;
this->ownerptr = user;
if ( queueused ) { NotifyOwner(); }
}
bool PS2Keyboard::PushKey(int key)
{
// Check if we need to allocate or resize the circular queue.
if ( queueused == queuelength )
{
size_t newqueuelength = (queuelength) ? queuelength * 2 : 32UL;
int* newqueue = new int[newqueuelength];
if ( !newqueue ) { return false; }
size_t elemsize = sizeof(*queue);
size_t leadingavai = queuelength-queueoffset;
size_t leading = (leadingavai < queueused) ? leadingavai : queueused;
size_t trailing = queueused - leading;
Memory::Copy(newqueue, queue + queueoffset, leading * elemsize);
Memory::Copy(newqueue + leading, queue, trailing * elemsize);
delete[] queue;
queue = newqueue;
queuelength = newqueuelength;
queueoffset = 0;
}
queue[(queueoffset + queueused++) % queuelength] = key;
return true;
}
int PS2Keyboard::PopKey()
{
if ( !queueused ) { return 0; }
int kbkey = queue[queueoffset];
queueoffset = (queueoffset + 1) % queuelength;
queueused--;
return kbkey;
}
int PS2Keyboard::Read()
{
return PopKey();
}
size_t PS2Keyboard::GetPending() const
{
return queueused;
}
bool PS2Keyboard::HasPending() const
{
return queueused;
}
}

69
sortix/kb/ps2.h Normal file
View File

@ -0,0 +1,69 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
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/ps2.h
A driver for the PS2 Keyboard.
******************************************************************************/
#ifndef SORTIX_KB_PS2_H
#define SORTIX_KB_PS2_H
#include "../keyboard.h"
namespace Sortix
{
class PS2Keyboard : public Keyboard
{
public:
PS2Keyboard(uint16_t iobase, uint8_t interrupt);
virtual ~PS2Keyboard();
virtual int Read();
virtual size_t GetPending() const;
virtual bool HasPending() const;
virtual void SetOwner(KeyboardOwner* owner, void* user);
public:
void OnInterrupt(CPU::InterruptRegisters* regs);
private:
uint8_t PopScancode();
int DecodeScancode(uint8_t scancode);
void UpdateLEDs(int ledval);
bool PushKey(int key);
int PopKey();
void NotifyOwner();
private:
int* queue;
size_t queuelength;
size_t queueoffset;
size_t queueused;
KeyboardOwner* owner;
void* ownerptr;
uint16_t iobase;
uint8_t interrupt;
bool scancodeescaped;
uint8_t leds;
};
}
#endif

142
sortix/kbapiadapter.cpp Normal file
View File

@ -0,0 +1,142 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
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/>.
kbapidapter.cpp
This class is a hack connecting the Keyboard and Keyboard layout classes
with the older and really bad Keyboard API. This class is intended to be
replaced by a real terminal driver working over /dev/tty descriptors.
******************************************************************************/
#include "platform.h"
#include <libmaxsi/keyboard.h>
#include "scheduler.h" // SIGINT
#include "keyboard.h"
#include "keycodes.h"
#include "kbapiadapter.h"
namespace Sortix
{
KBAPIAdapter::KBAPIAdapter(Keyboard* keyboard, KeyboardLayout* kblayout)
{
this->keyboard = keyboard;
this->kblayout = kblayout;
this->control = false;
this->queuelength = QUEUELENGTH;
this->queueused = 0;
this->queueoffset = 0;
keyboard->SetOwner(this, NULL);
}
KBAPIAdapter::~KBAPIAdapter()
{
delete keyboard;
delete kblayout;
}
void KBAPIAdapter::OnKeystroke(Keyboard* kb, void* /*user*/)
{
while ( kb->HasPending() )
{
ProcessKeystroke(kb->Read());
}
}
void KBAPIAdapter::ProcessKeystroke(int kbkey)
{
if ( !kbkey ) { return; }
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
uint32_t unicode = kblayout->Translate(kbkey);
// Now translate the keystroke into the older API's charset..
uint32_t maxsicode = (unicode) ? unicode : ToMaxsiCode(abskbkey);
if ( kbkey < 0 ) { maxsicode |= Maxsi::Keyboard::DEPRESSED; }
if ( kbkey == KBKEY_LCTRL ) { control = true; }
if ( kbkey == -KBKEY_LCTRL ) { control = false; }
if ( control && kbkey == KBKEY_C )
{
Scheduler::SigIntHack();
return;
}
if ( !QueueKeystroke(maxsicode) )
{
Log::PrintF("Warning: KBAPIAdapter driver dropping keystroke due "
"to insufficient buffer space\n");
}
}
uint32_t KBAPIAdapter::ToMaxsiCode(int abskbkey)
{
switch ( abskbkey )
{
case KBKEY_ESC: return Maxsi::Keyboard::ESC;
case KBKEY_LCTRL: return Maxsi::Keyboard::CTRL;
case KBKEY_LSHIFT: return Maxsi::Keyboard::LSHFT;
case KBKEY_RSHIFT: return Maxsi::Keyboard::RSHFT;
case KBKEY_LALT: return Maxsi::Keyboard::ALT;
case KBKEY_F1: return Maxsi::Keyboard::F1;
case KBKEY_F2: return Maxsi::Keyboard::F2;
case KBKEY_F3: return Maxsi::Keyboard::F3;
case KBKEY_F4: return Maxsi::Keyboard::F4;
case KBKEY_F5: return Maxsi::Keyboard::F5;
case KBKEY_F6: return Maxsi::Keyboard::F6;
case KBKEY_F7: return Maxsi::Keyboard::F7;
case KBKEY_F8: return Maxsi::Keyboard::F8;
case KBKEY_F9: return Maxsi::Keyboard::F9;
case KBKEY_F10: return Maxsi::Keyboard::F10;
case KBKEY_F11: return Maxsi::Keyboard::F11;
case KBKEY_F12: return Maxsi::Keyboard::F12;
case KBKEY_SCROLLLOCK: return Maxsi::Keyboard::SCRLCK;
case KBKEY_HOME: return Maxsi::Keyboard::HOME;
case KBKEY_UP: return Maxsi::Keyboard::UP;
case KBKEY_LEFT: return Maxsi::Keyboard::LEFT;
case KBKEY_RIGHT: return Maxsi::Keyboard::RIGHT;
case KBKEY_DOWN: return Maxsi::Keyboard::DOWN;
case KBKEY_PGUP: return Maxsi::Keyboard::PGUP;
case KBKEY_PGDOWN: return Maxsi::Keyboard::PGDOWN;
case KBKEY_END: return Maxsi::Keyboard::END;
case KBKEY_INSERT: return Maxsi::Keyboard::INS;
case KBKEY_DELETE: return Maxsi::Keyboard::DEL;
case KBKEY_CAPSLOCK: return Maxsi::Keyboard::CAPS;
case KBKEY_RALT: return Maxsi::Keyboard::ALTGR;
case KBKEY_NUMLOCK: return Maxsi::Keyboard::NUMLCK;
default: return Maxsi::Keyboard::UNKNOWN;
}
}
bool KBAPIAdapter::QueueKeystroke(uint32_t keystroke)
{
if ( queuelength <= queueused ) { return false; }
queue[(queueoffset + queueused++) % queuelength] = keystroke;
return true;
}
uint32_t KBAPIAdapter::DequeueKeystroke()
{
if ( !queueused ) { return 0; }
uint32_t codepoint = queue[queueoffset++];
queueoffset %= queuelength;
queueused--;
return codepoint;
}
}

63
sortix/kbapiadapter.h Normal file
View File

@ -0,0 +1,63 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
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/>.
kbapidapter.h
This class is a hack connecting the Keyboard and Keyboard layout classes
with the older and really bad Keyboard API. This class is intended to be
replaced by a real terminal driver working over /dev/tty descriptors.
******************************************************************************/
#ifndef SORTIX_KBAPIADAPTER_H
#define SORTIX_KBAPIADAPTER_H
#include "keyboard.h"
namespace Sortix
{
class KBAPIAdapter : public KeyboardOwner
{
public:
KBAPIAdapter(Keyboard* keyboard, KeyboardLayout* kblayout);
virtual ~KBAPIAdapter();
virtual void OnKeystroke(Keyboard* keyboard, void* user);
public:
uint32_t DequeueKeystroke();
private:
void ProcessKeystroke(int kbkey);
bool QueueKeystroke(uint32_t keystroke);
static uint32_t ToMaxsiCode(int abskbkey);
private:
Keyboard* keyboard;
KeyboardLayout* kblayout;
bool control;
static const size_t QUEUELENGTH = 1024UL;
size_t queuelength;
size_t queueused;
size_t queueoffset;
uint32_t queue[QUEUELENGTH];
};
}
#endif

View File

@ -1,6 +1,6 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
This file is part of Sortix.
@ -18,721 +18,39 @@
with Sortix. If not, see <http://www.gnu.org/licenses/>.
keyboard.cpp
A driver for the PS2 Keyboard.
An interface to keyboards.
******************************************************************************/
#include "platform.h"
#include <libmaxsi/memory.h>
#include <libmaxsi/keyboard.h>
#include "log.h"
#include "panic.h"
#include "keyboard.h"
#include "interrupt.h"
#include "scheduler.h"
#include "syscall.h"
using namespace Maxsi::Keyboard;
#include "keyboard.h"
#include "kb/ps2.h"
#include "kb/layout/us.h"
#include "kbapiadapter.h"
namespace Sortix
{
namespace Keyboard
KBAPIAdapter* tty;
uint32_t SysReceiveKeystroke()
{
namespace Layouts
{
namespace US
{
uint32_t sg[128] =
{
UNKNOWN,
ESC,
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'0',
'-',
'=',
'\b',
'\t',
'q',
'w',
'e',
'r',
't',
'y',
'u',
'i',
'o',
'p',
'[',
']',
'\n',
CTRL,
'a',
's',
'd',
'f',
'g',
'h',
'j',
'k',
'l',
';',
'\'',
'`',
LSHFT,
'\\',
'z',
'x',
'c',
'v',
'b',
'n',
'm',
',',
'.',
'/',
RSHFT,
'*',
ALT,
' ',
CAPS,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
NUMLCK,
SCRLCK,
HOME,
UP,
PGUP,
'-',
LEFT,
UNKNOWN,
RIGHT,
'+',
END,
DOWN,
PGDOWN,
INS,
DEL,
UNKNOWN,
UNKNOWN,
UNKNOWN,
F11,
F12,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
};
return tty->DequeueKeystroke();
}
uint32_t Sg[128] =
{
UNKNOWN,
ESC,
'!',
'@',
'#',
'$',
'%',
'^',
'&',
'*',
'(',
')',
'_',
'+',
'\b',
'\t', // TODO: Make it de-tab!
'Q',
'W',
'E',
'R',
'T',
'Y',
'U',
'I',
'O',
'P',
'{',
'}',
'\n',
CTRL,
'A',
'S',
'D',
'F',
'G',
'H',
'J',
'K',
'L',
':',
'"',
'~',
LSHFT,
'|',
'Z',
'X',
'C',
'V',
'B',
'N',
'M',
'<',
'>',
'?',
RSHFT,
'*',
ALT,
' ',
CAPS,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
NUMLCK,
SCRLCK,
HOME,
UP,
PGUP,
'-',
LEFT,
UNKNOWN,
RIGHT,
'+',
END,
DOWN,
PGDOWN,
INS,
DEL,
UNKNOWN,
UNKNOWN,
UNKNOWN,
F11,
F12,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
};
void Keyboard::Init()
{
Keyboard* keyboard = new PS2Keyboard(0x60, Interrupt::IRQ1);
if ( !keyboard ) { Panic("Could not allocate PS2 Keyboard driver"); }
uint32_t sG[128] =
{
UNKNOWN,
ESC,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
'\b',
'\t',
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
'\n',
CTRL,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
LSHFT,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
RSHFT,
UNKNOWN,
ALT,
' ',
CAPS,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
NUMLCK,
SCRLCK,
HOME,
UP,
PGUP,
'-',
LEFT,
UNKNOWN,
RIGHT,
'+',
END,
DOWN,
PGDOWN,
INS,
DEL,
UNKNOWN,
UNKNOWN,
UNKNOWN,
F11,
F12,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
};
KeyboardLayout* kblayout = new KBLayoutUS;
if ( !kblayout ) { Panic("Could not allocate keyboard layout driver"); }
uint32_t SG[128] =
{
UNKNOWN,
ESC,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
'\b',
'\t',
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
'\n',
CTRL,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
LSHFT,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
RSHFT,
UNKNOWN,
ALT,
' ',
CAPS,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
NUMLCK,
SCRLCK,
HOME,
UP,
PGUP,
'-',
LEFT,
UNKNOWN,
RIGHT,
'+',
END,
DOWN,
PGDOWN,
INS,
DEL,
UNKNOWN,
UNKNOWN,
UNKNOWN,
F11,
F12,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
UNKNOWN,
};
tty = new KBAPIAdapter(keyboard, kblayout);
if ( !tty ) { Panic("Could not allocate a simple terminal"); }
uint32_t* Layout[4] = { sg, Sg, sG, SG };
}
uint32_t** Layout = US::Layout;
nat Mask;
nat LockMask;
bool control;
void Init()
{
Mask = 0;
LockMask = 0;
control = false;
}
const nat Shift = (1<<0);
const nat AltGr = (1<<1);
const nat ScrLck = (1<<2);
const nat LEDScrLck = (1<<0);
const nat LEDNumLck = (1<<1);
const nat LEDCapsLck = (1<<2);
uint32_t GetCodePoint(uint8_t Scancode)
{
nat TableIndex = 0x3 & (Mask ^ LockMask);
//Log::PrintF("[m=%x,lm=%x,ti=%x]", Mask, LockMask, TableIndex);
uint32_t CodePoint = Layout[TableIndex][Scancode & 0x7F];
if ( CodePoint == UNKNOWN ) { return UNKNOWN; }
if ( Scancode & 0x80 )
{
if ( CodePoint == LSHFT ) { Mask &= ~Shift; }
if ( CodePoint == ALTGR ) { Mask &= ~AltGr; }
if ( CodePoint == SCRLCK ) { Mask &= ~ScrLck; }
if ( CodePoint == CTRL ) { control = false; }
}
else
{
if ( CodePoint == LSHFT ) { Mask |= Shift; }
if ( CodePoint == ALTGR ) { Mask |= AltGr; }
if ( CodePoint == SCRLCK ) { Mask |= ScrLck; }
if ( CodePoint == CAPS ) { LockMask ^= Shift; SetLEDs(LEDCapsLck); }
if ( CodePoint == CTRL ) { control = true; }
}
if ( control && ( CodePoint == 'c' || CodePoint == 'C' ) )
{
CodePoint = SIGINT;
}
return CodePoint;
}
}
uint8_t LEDs;
size_t keystrokeQueueOffset;
size_t keystrokeQueueUsed;
size_t keystrokeQueueLength;
uint32_t* keystrokeQueue;
uint32_t SysReceiveKeystroke()
{
if ( keystrokeQueueUsed == 0 ) { return 0; }
uint32_t codepoint = keystrokeQueue[keystrokeQueueOffset++];
keystrokeQueueOffset %= keystrokeQueueLength;
keystrokeQueueUsed--;
return codepoint;
}
void Init()
{
// Initialize variables.
LEDs = 0;
Layouts::Init();
// Register our keystroke callback.
Interrupt::RegisterHandler(Interrupt::IRQ1, OnIRQ1, NULL);
// If any scancodes were already pending, our interrupt handler
// will never be called. Let's just discard anything pending.
CPU::InPortB(0x60);
// Create a queue where pending keystrokes can be stored until
// user-space applications access them.
keystrokeQueueUsed = 0;
keystrokeQueueOffset = 0;
keystrokeQueueLength = 1024ULL;
keystrokeQueue = new uint32_t[keystrokeQueueLength];
if ( keystrokeQueue == NULL )
{
Panic("Could not allocate keystroke buffer");
}
Syscall::Register(SYSCALL_RECEIVE_KEYSTROKE, (void*) SysReceiveKeystroke);
}
bool QueueKeystroke(uint32_t keystroke)
{
if ( keystrokeQueueLength <= keystrokeQueueUsed ) { return false; }
size_t position = keystrokeQueueOffset + keystrokeQueueUsed;
position %= keystrokeQueueLength;
keystrokeQueueUsed++;
keystrokeQueue[position] = keystroke;
return true;
}
void OnIRQ1(CPU::InterruptRegisters* Regs, void* user)
{
// Read the scancode from the data register.
uint8_t Scancode = CPU::InPortB(0x60);
//Log::PrintF("[%u]", Scancode);
uint32_t CodePoint = Layouts::GetCodePoint(Scancode);
if ( CodePoint == SIGINT )
{
Scheduler::SigIntHack();
return;
}
bool KeyUp = (Scancode & 0x80);
if ( KeyUp ) { CodePoint |= DEPRESSED; }
QueueKeystroke(CodePoint);
return;
//if ( Reader != NULL ) { Reader->OnKeystroke(CodePoint, KeyUp); return; }
// Use this to debug the exact scancodes you receive!
//Log::PrintF("[%u/U+%x]", Scancode, CodePoint);
if ( CodePoint == UNKNOWN ) { Log::PrintF("^%u", Scancode);return; }
if ( CodePoint & (1<<31) ) { return; }
// The high bit of the scancode is set if the key is released.
if ( Scancode & 0x80 ) { return; }
if ( CodePoint & 0xFFFFFF80 ) { Log::PrintF("U+%x", CodePoint); return; }
Log::PrintF("%s", &CodePoint); // Little endian hack!
}
void SetLEDs(uint8_t Toggle)
{
LEDs ^= Toggle;
while ( (CPU::InPortB(0x64) & (1<<1)) != 0 ) { } //loop Until zero
CPU::OutPortB(0x60, 0xED);
while ( (CPU::InPortB(0x64) & (1<<1)) != 0 ) { } //loop Until zero
CPU::OutPortB(0x60, LEDs);
}
Syscall::Register(SYSCALL_RECEIVE_KEYSTROKE, (void*) SysReceiveKeystroke);
}
}

View File

@ -1,6 +1,6 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
This file is part of Sortix.
@ -18,7 +18,7 @@
with Sortix. If not, see <http://www.gnu.org/licenses/>.
keyboard.h
A driver for the PS2 Keyboard.
An interface to keyboards.
******************************************************************************/
@ -27,13 +27,35 @@
namespace Sortix
{
namespace Keyboard
class Keyboard;
class KeyboardOwner;
class Keyboard
{
void Init();
void SetLEDs(uint8_t Toggle);
void OnIRQ1(CPU::InterruptRegisters* Regs, void* user);
bool QueueKeystroke(uint32_t keystroke);
}
public:
static void Init();
public:
virtual ~Keyboard() { }
virtual int Read() = 0;
virtual size_t GetPending() const = 0;
virtual bool HasPending() const = 0;
virtual void SetOwner(KeyboardOwner* owner, void* user) = 0;
};
class KeyboardOwner
{
public:
virtual ~KeyboardOwner() { }
virtual void OnKeystroke(Keyboard* keyboard, void* user) = 0;
};
class KeyboardLayout
{
public:
virtual ~KeyboardLayout() { }
virtual uint32_t Translate(int kbkey) = 0;
};
}
#endif

145
sortix/keycodes.h Normal file
View File

@ -0,0 +1,145 @@
/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
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/>.
keycodes.h
Defines codes for every logical key on keyboards.
******************************************************************************/
#ifndef SORTIX_KEYCODES_H
#define SORTIX_KEYCODES_H
/* Each of these keycodes corrospond to a logical key on a keyboard. Code
reading logical keystrokes from the keyboard will receive a code from this
list when the key is pressed, and a negative version of the same key when it
is released by the user. */
#define KBKEY_ESC 0x01
#define KBKEY_NUM1 0x02
#define KBKEY_NUM2 0x03
#define KBKEY_NUM3 0x04
#define KBKEY_NUM4 0x05
#define KBKEY_NUM5 0x06
#define KBKEY_NUM6 0x07
#define KBKEY_NUM7 0x08
#define KBKEY_NUM8 0x09
#define KBKEY_NUM9 0x0A
#define KBKEY_NUM0 0x0B
#define KBKEY_SYM1 0x0C
#define KBKEY_SYM2 0x0D
#define KBKEY_BKSPC 0x0E
#define KBKEY_TAB 0x0F
#define KBKEY_Q 0x10
#define KBKEY_W 0x11
#define KBKEY_E 0x12
#define KBKEY_R 0x13
#define KBKEY_T 0x14
#define KBKEY_Y 0x15
#define KBKEY_U 0x16
#define KBKEY_I 0x17
#define KBKEY_O 0x18
#define KBKEY_P 0x19
#define KBKEY_SYM3 0x1A
#define KBKEY_SYM4 0x1B
#define KBKEY_ENTER 0x1C
#define KBKEY_LCTRL 0x1D
#define KBKEY_A 0x1E
#define KBKEY_S 0x1F
#define KBKEY_D 0x20
#define KBKEY_F 0x21
#define KBKEY_G 0x22
#define KBKEY_H 0x23
#define KBKEY_J 0x24
#define KBKEY_K 0x25
#define KBKEY_L 0x26
#define KBKEY_SYM5 0x27
#define KBKEY_SYM6 0x28
#define KBKEY_SYM7 0x29
#define KBKEY_LSHIFT 0x2A
#define KBKEY_SYM8 0x2B
#define KBKEY_Z 0x2C
#define KBKEY_X 0x2D
#define KBKEY_C 0x2E
#define KBKEY_V 0x2F
#define KBKEY_B 0x30
#define KBKEY_N 0x31
#define KBKEY_M 0x32
#define KBKEY_SYM9 0x33
#define KBKEY_SYM10 0x34
#define KBKEY_SYM11 0x35
#define KBKEY_RSHIFT 0x36
#define KBKEY_SYM12 0x37
#define KBKEY_LALT 0x38
#define KBKEY_SPACE 0x39
#define KBKEY_CAPSLOCK 0x3A
#define KBKEY_F1 0x3B
#define KBKEY_F2 0x3C
#define KBKEY_F3 0x3D
#define KBKEY_F4 0x3E
#define KBKEY_F5 0x3F
#define KBKEY_F6 0x40
#define KBKEY_F7 0x41
#define KBKEY_F8 0x42
#define KBKEY_F9 0x43
#define KBKEY_F10 0x44
#define KBKEY_NUMLOCK 0x45
#define KBKEY_SCROLLLOCK 0x46
#define KBKEY_KPAD7 0x47
#define KBKEY_KPAD8 0x48
#define KBKEY_KPAD9 0x49
#define KBKEY_SYM13 0x4A
#define KBKEY_KPAD4 0x4B
#define KBKEY_KPAD5 0x4C
#define KBKEY_KPAD6 0x4D
#define KBKEY_SYM14 0x4E
#define KBKEY_KPAD1 0x4F
#define KBKEY_KPAD2 0x50
#define KBKEY_KPAD3 0x51
#define KBKEY_KPAD0 0x52
#define KBKEY_SYM15 0x53
#define KBKEY_ALTSYSRQ 0x54
#define KBKEY_NO_STANDARD_MEANING_1 0x55 /* Sometimes F11, F12, or even FN */
#define KBKEY_NO_STANDARD_MEANING_2 0x56 /* Possibly Windows key? */
#define KBKEY_F11 0x57
#define KBKEY_F12 0x58
/* [0x59, 0x7F] are not really standard. */
#define KBKEY_KPADENTER (0x80 + 0x1C)
#define KBKEY_RCTRL (0x80 + 0x1D)
#define KBKEY_FAKELSHIFT (0x80 + 0x2A)
#define KBKEY_SYM16 (0x80 + 0x35)
#define KBKEY_FAKERSHIFT (0x80 + 0x36)
#define KBKEY_CTRLPRINTSCRN (0x80 + 0x37)
#define KBKEY_RALT (0x80 + 0x38)
#define KBKEY_CTRLBREAK (0x80 + 0x46)
#define KBKEY_HOME (0x80 + 0x47)
#define KBKEY_UP (0x80 + 0x48)
#define KBKEY_PGUP (0x80 + 0x49)
#define KBKEY_LEFT (0x80 + 0x4B)
#define KBKEY_RIGHT (0x80 + 0x4D)
#define KBKEY_END (0x80 + 0x4F)
#define KBKEY_DOWN (0x80 + 0x50)
#define KBKEY_PGDOWN (0x80 + 0x51)
#define KBKEY_INSERT (0x80 + 0x52)
#define KBKEY_DELETE (0x80 + 0x53)
#define KBKEY_LSUPER (0x80 + 0x5B)
#define KBKEY_RSUPER (0x80 + 0x5C)
#define KBKEY_MENU (0x80 + 0x5D)
#endif

View File

@ -69,6 +69,13 @@ namespace Sortix
int c;
while ( (c=UART::TryPopChar()) != -1 )
{
#warning Support for hooking the serial input up against the keyboard API have broken
#if 0
// TODO: This is no longer compatible with the keyboard API, so
// it has been commented out. Besides, JSSortix isn't really
// supported anyway. It'd be nice to refactor this into a
// SerialKeyboard class or something.
using namespace Maxsi::Keyboard;
if ( !isEsc && c == '\e' ) { isEsc = true; continue; }
@ -121,6 +128,7 @@ namespace Sortix
c &= ~(1<<7); c |= DEPRESSED;
}
Keyboard::QueueKeystroke(c);
#endif
}
}