* Work in progress commit of the Keymap rework. Should not disturb the
existing code. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29666 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,694 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "KeyboardLayout.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <File.h>
|
||||||
|
|
||||||
|
|
||||||
|
//#define TRACE_LAYOUT
|
||||||
|
#ifdef TRACE_LAYOUT
|
||||||
|
# define TRACE(x...) printf(x)
|
||||||
|
#else
|
||||||
|
# define TRACE(x...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
KeyboardLayout::KeyboardLayout()
|
||||||
|
:
|
||||||
|
fKeys(NULL),
|
||||||
|
fKeyCount(0),
|
||||||
|
fKeyCapacity(0)
|
||||||
|
{
|
||||||
|
_SetDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KeyboardLayout::~KeyboardLayout()
|
||||||
|
{
|
||||||
|
free(fKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
KeyboardLayout::Name()
|
||||||
|
{
|
||||||
|
return fName.String();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
KeyboardLayout::CountKeys()
|
||||||
|
{
|
||||||
|
return fKeyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Key*
|
||||||
|
KeyboardLayout::KeyAt(int32 index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= fKeyCount)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &fKeys[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Key*
|
||||||
|
KeyboardLayout::KeyAt(BPoint point)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
KeyboardLayout::Bounds()
|
||||||
|
{
|
||||||
|
return fBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
KeyboardLayout::Load(const char* path)
|
||||||
|
{
|
||||||
|
BFile file;
|
||||||
|
status_t status = file.SetTo(path, B_READ_ONLY);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
off_t size;
|
||||||
|
status = file.GetSize(&size);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (size > 65536) {
|
||||||
|
// We don't accept files larger than this
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = (char*)malloc(size + 1);
|
||||||
|
if (data == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
ssize_t bytesRead = file.Read(data, size);
|
||||||
|
if (bytesRead != size) {
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
if (bytesRead < 0)
|
||||||
|
return bytesRead;
|
||||||
|
|
||||||
|
return B_IO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[size] = '\0';
|
||||||
|
|
||||||
|
status = _InitFrom(data);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayout::_SetDefault()
|
||||||
|
{
|
||||||
|
static const char* kDefaultLayout104 = "name = 104 Keys\n"
|
||||||
|
// Size shortcuts
|
||||||
|
"default-size = 10,10\n"
|
||||||
|
"$b = 5,10\n"
|
||||||
|
"$c = 20,10\n"
|
||||||
|
"$d = 15,10\n"
|
||||||
|
"$enter = d20,10\n"
|
||||||
|
"$f = 10,20\n"
|
||||||
|
"$g = 13,10\n"
|
||||||
|
// Key rows
|
||||||
|
"[ 0,0; d:0x01; :-; :+4; $b:-; d:+4; $b:-; :+4; $b:-; d:+3 ]\n"
|
||||||
|
"[ 0,20; :+13; d$c:+; $b:-; d:+3; $b:-; d:+4 ]\n"
|
||||||
|
"[ 0,30; d$d:0x26; :+12; $d:+1; $b:-; d:+3; $b:-; :+3; "
|
||||||
|
"d$f:+1 ]\n"
|
||||||
|
"[ 0,40; d$c:0x3b; :+11; $enter:+1; 40,10:-; :+3 ]\n"
|
||||||
|
"[ 0,50; d24,10:0x4b; :+10; d26,10:+1; 15,10:-; d:+1; "
|
||||||
|
" 15,10:-; :+3; d$f:+1 ]\n"
|
||||||
|
"[ 0,60; d$g:0x5c; d$g:0x66; d$g:0x5d; 59,10:+1; d$g:+1; d$g:0x67+1; "
|
||||||
|
"d$g:0x60; $b:-; d:+3; $b:-; $c:+1; :+1 ]\n";
|
||||||
|
#if 0
|
||||||
|
static const char* kDefaultLayout105 = "name = 105 Keys International\n"
|
||||||
|
// Size shortcuts
|
||||||
|
"default-size = 10,10\n"
|
||||||
|
"$b = 5,10\n"
|
||||||
|
"$c = 20,10\n"
|
||||||
|
"$d = 15,10\n"
|
||||||
|
"$e = l15,20,13\n"
|
||||||
|
"$f = 10,20\n"
|
||||||
|
"$g = 13,10\n"
|
||||||
|
// Key rows
|
||||||
|
"[ 0,0; d:0x01; :-; :+4; $b:-; d:+4; $b:-; :+4; $b:-; d:+3 ]\n"
|
||||||
|
"[ 0,20; :+13; d$c:+; $b:-; d:+3; $b:-; d:+4 ]\n"
|
||||||
|
"[ 0,30; d$d:0x26; :+12; d$e:0x47; $b:-; d:0x34-0x36; $b:-; :+3; "
|
||||||
|
"d$f:+1 ]\n"
|
||||||
|
"[ 0,40; d19,10:0x3b; :+11; :0x33; 51,10:-; :0x48-0x4a ]\n"
|
||||||
|
"[ 0,50; d$g:0x4b; :0x69; :0x4c+9; d27,10:+1; 15,10:-; d:+1; "
|
||||||
|
" 15,10:-; :+3; d$f:+1 ]\n"
|
||||||
|
"[ 0,60; d$g:0x5c; d$g:0x66; d$g:0x5d; 59,10:+1; d$g:+1; d$g:0x67+1; "
|
||||||
|
"d$g:0x60; $b:-; d:+3; $b:-; $c:+1; :+1 ]\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_InitFrom(kDefaultLayout104);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayout::_FreeKeys()
|
||||||
|
{
|
||||||
|
free(fKeys);
|
||||||
|
fKeys = NULL;
|
||||||
|
fKeyCount = 0;
|
||||||
|
fKeyCapacity = 0;
|
||||||
|
fBounds = BRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayout::_Error(const parse_state& state, const char* reason, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, reason);
|
||||||
|
|
||||||
|
fprintf(stderr, "Syntax error in line %ld: ", state.line);
|
||||||
|
vfprintf(stderr, reason, args);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayout::_AddAlternateKeyCode(Key* key, int32 modifier, int32 code)
|
||||||
|
{
|
||||||
|
if (key == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: search for free spot
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_AddKey(const Key& key)
|
||||||
|
{
|
||||||
|
TRACE(" add %ld (%g,%g)\n", key.code, key.frame.left, key.frame.top);
|
||||||
|
if (fKeyCount + 1 > fKeyCapacity) {
|
||||||
|
// enlarge array
|
||||||
|
int32 newCapacity = fKeyCapacity + 32;
|
||||||
|
Key* newKeys = (Key*)realloc(fKeys, newCapacity * sizeof(Key));
|
||||||
|
if (newKeys == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fKeys = newKeys;
|
||||||
|
fKeyCapacity = newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
fKeys[fKeyCount] = key;
|
||||||
|
fKeyCount++;
|
||||||
|
|
||||||
|
fBounds = key.frame | fBounds;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayout::_SkipCommentsAndSpace(parse_state& state, const char*& data)
|
||||||
|
{
|
||||||
|
while (data[0] != '\0') {
|
||||||
|
while (isspace(data[0])) {
|
||||||
|
if (data[0] == '\n')
|
||||||
|
state.line++;
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] == '#') {
|
||||||
|
// skip comment
|
||||||
|
while (data[0] != '\0' && data[0] != '\n') {
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayout::_Trim(BString& string, bool stripComments)
|
||||||
|
{
|
||||||
|
// Strip leading spaces
|
||||||
|
int32 i = 0;
|
||||||
|
while (isspace(string[i])) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i > 0)
|
||||||
|
string.Remove(0, i);
|
||||||
|
|
||||||
|
// Remove comments
|
||||||
|
if (stripComments) {
|
||||||
|
i = string.FindFirst('#');
|
||||||
|
if (i >= 0)
|
||||||
|
string.Truncate(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip trailing spaces
|
||||||
|
i = string.Length() - 1;
|
||||||
|
while (i > 0 && isspace(string[i])) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
string.Truncate(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_GetPair(const parse_state& state, const char*& data,
|
||||||
|
BString& name, BString& value)
|
||||||
|
{
|
||||||
|
// Get name
|
||||||
|
name = "";
|
||||||
|
while (data[0] != '\0' && data[0] != '=') {
|
||||||
|
name += data[0];
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] != '=') {
|
||||||
|
_Error(state, "no valid pair");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip sign
|
||||||
|
data++;
|
||||||
|
|
||||||
|
// Get value
|
||||||
|
value = "";
|
||||||
|
while (data[0] != '\0' && data[0] != '\n') {
|
||||||
|
value += data[0];
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Trim(name, false);
|
||||||
|
_Trim(value, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_AddKeyCodes(const parse_state& state, BPoint& rowLeftTop,
|
||||||
|
Key& key, const char* data, int32& lastCount)
|
||||||
|
{
|
||||||
|
if (data[0] == '-') {
|
||||||
|
// no key, just free space
|
||||||
|
int32 num = strtoul(data + 1, NULL, 0);
|
||||||
|
if (num < 1)
|
||||||
|
num = 1;
|
||||||
|
else if (num > 32) {
|
||||||
|
_Error(state, "empty key count too large");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
key.frame.OffsetTo(rowLeftTop);
|
||||||
|
rowLeftTop.x = key.frame.left + key.frame.Width() * num;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 modifier = 0;
|
||||||
|
|
||||||
|
if (isalpha(data[0])) {
|
||||||
|
// TODO: get modifier (ie. "num")
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 first;
|
||||||
|
int32 last;
|
||||||
|
int32 num = 1;
|
||||||
|
|
||||||
|
if (data[0] == '+') {
|
||||||
|
num = strtoul(data + 1, NULL, 0);
|
||||||
|
if (num < 1)
|
||||||
|
num = 1;
|
||||||
|
else if (num > 32) {
|
||||||
|
_Error(state, "key count too large");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fKeyCount > 0)
|
||||||
|
first = fKeys[fKeyCount - 1].code + 1;
|
||||||
|
else
|
||||||
|
first = 1;
|
||||||
|
|
||||||
|
last = first + num - 1;
|
||||||
|
} else {
|
||||||
|
char* end;
|
||||||
|
first = strtoul(data, &end, 0);
|
||||||
|
last = first;
|
||||||
|
|
||||||
|
if (end[0] == '-') {
|
||||||
|
last = strtoul(end + 1, NULL, 0);
|
||||||
|
if (first > last) {
|
||||||
|
_Error(state, "invalid key code specifier");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = last - first;
|
||||||
|
} else if (end[0] == '+') {
|
||||||
|
num = strtoul(end + 1, NULL, 0) + 1;
|
||||||
|
last = first + num - 1;
|
||||||
|
} else if (end[0] != '\0') {
|
||||||
|
_Error(state, "invalid key range");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCount != 0) {
|
||||||
|
// update existing keys
|
||||||
|
if (lastCount != num) {
|
||||||
|
_Error(state, "modifier key mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 i = fKeyCount - num; i < fKeyCount; i++, first++) {
|
||||||
|
Key* key = KeyAt(i);
|
||||||
|
|
||||||
|
_AddAlternateKeyCode(key, modifier, first);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// add new keys
|
||||||
|
for (int32 i = first; i <= last; i++) {
|
||||||
|
key.code = i;
|
||||||
|
|
||||||
|
// "layout"
|
||||||
|
key.frame.OffsetTo(rowLeftTop);
|
||||||
|
rowLeftTop.x = key.frame.right;
|
||||||
|
|
||||||
|
_AddKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCount = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_GetSize(const parse_state& state, const char* data,
|
||||||
|
float& x, float& y, float* _secondRow)
|
||||||
|
{
|
||||||
|
if (data[0] == '\0') {
|
||||||
|
// default size
|
||||||
|
x = fDefaultKeySize.width;
|
||||||
|
y = fDefaultKeySize.height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float secondRow = 0;
|
||||||
|
int num = sscanf(data, "%g,%g,%g", &x, &y, &secondRow);
|
||||||
|
if (num < 2) {
|
||||||
|
_Error(state, "invalid size");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_secondRow != NULL)
|
||||||
|
*_secondRow = secondRow;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_GetShape(const parse_state& state, const char* data, Key& key)
|
||||||
|
{
|
||||||
|
// the default
|
||||||
|
key.shape = kRectangleKeyShape;
|
||||||
|
key.dark = false;
|
||||||
|
|
||||||
|
while (isalpha(data[0])) {
|
||||||
|
switch (tolower(data[0])) {
|
||||||
|
case 'r':
|
||||||
|
key.shape = kRectangleKeyShape;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
key.shape = kCircleKeyShape;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
key.shape = kEnterKeyShape;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
key.dark = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_Error(state, "unknown shape specifier '%c'", data[0]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
float width, height;
|
||||||
|
if (!_GetSize(state, data, width, height, &key.second_row))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// don't accept second row with anything but kEnterKeyShape
|
||||||
|
if ((key.shape != kEnterKeyShape && key.second_row != 0)
|
||||||
|
|| (key.shape == kEnterKeyShape && key.second_row == 0)) {
|
||||||
|
_Error(state, "shape size mismatch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
key.frame.left = 0;
|
||||||
|
key.frame.top = 0;
|
||||||
|
key.frame.right = width;
|
||||||
|
key.frame.bottom = height;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
KeyboardLayout::_Delimiter(parse_mode mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
default:
|
||||||
|
case kSize:
|
||||||
|
return "";
|
||||||
|
case kRowStart:
|
||||||
|
return ";";
|
||||||
|
|
||||||
|
case kKeyShape:
|
||||||
|
return ":";
|
||||||
|
case kKeyCodes:
|
||||||
|
return ";:";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_GetTerm(const char*& data, const char* delimiter,
|
||||||
|
BString& term, bool closingBracketAllowed)
|
||||||
|
{
|
||||||
|
// Get term
|
||||||
|
term = "";
|
||||||
|
while (data[0] != '\0' && strchr(delimiter, data[0]) == NULL
|
||||||
|
&& data[0] != '\n' && data[0] != '#'
|
||||||
|
&& (!closingBracketAllowed || data[0] != ']')) {
|
||||||
|
term += data[0];
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] == '\0' && delimiter[0])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_Trim(term, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_SubstituteVariables(BString& term, VariableMap& variables,
|
||||||
|
BString& unknown)
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
int32 index = term.FindFirst('$');
|
||||||
|
if (index < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// find variable name
|
||||||
|
|
||||||
|
VariableMap::iterator iterator = variables.begin();
|
||||||
|
for (; iterator != variables.end(); iterator++) {
|
||||||
|
const BString& name = iterator->first;
|
||||||
|
if (!name.Compare(&term[index], name.Length())) {
|
||||||
|
// got one, replace it
|
||||||
|
term.Remove(index, name.Length());
|
||||||
|
term.Insert(iterator->second.String(), index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterator == variables.end()) {
|
||||||
|
// variable has not been found
|
||||||
|
unknown = &term[index];
|
||||||
|
int32 length = 1;
|
||||||
|
while (isalpha(unknown[length])) {
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
unknown.Truncate(length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayout::_ParseTerm(const parse_state& state, const char*& data,
|
||||||
|
BString& term, VariableMap& variables)
|
||||||
|
{
|
||||||
|
if (!_GetTerm(data, _Delimiter(state.mode), term,
|
||||||
|
state.mode == kKeyCodes)) {
|
||||||
|
_Error(state, state.mode == kRowStart
|
||||||
|
? "no valid row start" : "invalid term");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString unknown;
|
||||||
|
if (!_SubstituteVariables(term, variables, unknown)) {
|
||||||
|
_Error(state, "Unknown variable \"%s\"", unknown.String());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
KeyboardLayout::_InitFrom(const char* data)
|
||||||
|
{
|
||||||
|
_FreeKeys();
|
||||||
|
|
||||||
|
VariableMap variables;
|
||||||
|
BPoint rowLeftTop;
|
||||||
|
int32 lastKeyCount = 0;
|
||||||
|
Key key;
|
||||||
|
|
||||||
|
parse_state state = {kPairs, 1};
|
||||||
|
|
||||||
|
while (data[0] != '\0') {
|
||||||
|
_SkipCommentsAndSpace(state, data);
|
||||||
|
|
||||||
|
if (data[0] == '[') {
|
||||||
|
state.mode = kRowStart;
|
||||||
|
|
||||||
|
rowLeftTop = BPoint(0, 0);
|
||||||
|
data++;
|
||||||
|
continue;
|
||||||
|
} else if (data[0] == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (state.mode) {
|
||||||
|
case kPairs:
|
||||||
|
{
|
||||||
|
BString name;
|
||||||
|
BString value;
|
||||||
|
if (!_GetPair(state, data, name, value))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
TRACE("<%s> = <%s>\n", name.String(), value.String());
|
||||||
|
if (name == "name")
|
||||||
|
fName = value;
|
||||||
|
else if (name == "default-size") {
|
||||||
|
const char* valueString = value.String();
|
||||||
|
parse_state tempState = {kSize, state.line};
|
||||||
|
BString term;
|
||||||
|
if (!_ParseTerm(tempState, valueString, term, variables))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
TRACE(" size = %s\n", term.String());
|
||||||
|
if (!_GetSize(state, term.String(), fDefaultKeySize.width,
|
||||||
|
fDefaultKeySize.height))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
} else if (name[0] == '$')
|
||||||
|
variables[name] = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kRowStart:
|
||||||
|
case kKeyShape:
|
||||||
|
case kKeyCodes:
|
||||||
|
{
|
||||||
|
if (data[0] == ']') {
|
||||||
|
if (state.mode == kKeyShape) {
|
||||||
|
state.mode = kPairs;
|
||||||
|
data++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_Error(state, "unexpected row closing bracket");
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString term;
|
||||||
|
if (!_ParseTerm(state, data, term, variables))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
switch (state.mode) {
|
||||||
|
case kRowStart:
|
||||||
|
if (!_GetSize(state, term.String(), rowLeftTop.x,
|
||||||
|
rowLeftTop.y))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
TRACE("row: %s (%g:%g)\n", term.String(), rowLeftTop.x,
|
||||||
|
rowLeftTop.y);
|
||||||
|
|
||||||
|
state.mode = kKeyShape;
|
||||||
|
break;
|
||||||
|
case kKeyShape:
|
||||||
|
memset(&key, 0, sizeof(Key));
|
||||||
|
if (!_GetShape(state, term.String(), key))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
TRACE(" shape: %s (%g:%g:%g)\n", term.String(),
|
||||||
|
key.frame.Width(), key.frame.Height(),
|
||||||
|
key.second_row);
|
||||||
|
|
||||||
|
lastKeyCount = 0;
|
||||||
|
state.mode = kKeyCodes;
|
||||||
|
break;
|
||||||
|
case kKeyCodes:
|
||||||
|
TRACE(" raw key: %s\n", term.String());
|
||||||
|
|
||||||
|
if (!_AddKeyCodes(state, rowLeftTop, key, term.String(),
|
||||||
|
lastKeyCount))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (data[0] != ':')
|
||||||
|
state.mode = kKeyShape;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data[0] != ']' && data[0] != '\0')
|
||||||
|
data++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef KEYBOARD_LAYOUT_H
|
||||||
|
#define KEYBOARD_LAYOUT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <Point.h>
|
||||||
|
#include <Rect.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum key_shape {
|
||||||
|
kRectangleKeyShape,
|
||||||
|
kCircleKeyShape,
|
||||||
|
kEnterKeyShape
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Key {
|
||||||
|
int32 code;
|
||||||
|
int32 alternate_code[3];
|
||||||
|
int32 alternate_modifier[3];
|
||||||
|
key_shape shape;
|
||||||
|
BRect frame;
|
||||||
|
float second_row;
|
||||||
|
bool dark;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<BString, BString> VariableMap;
|
||||||
|
|
||||||
|
class KeyboardLayout {
|
||||||
|
public:
|
||||||
|
KeyboardLayout();
|
||||||
|
~KeyboardLayout();
|
||||||
|
|
||||||
|
const char* Name();
|
||||||
|
|
||||||
|
int32 CountKeys();
|
||||||
|
Key* KeyAt(int32 index);
|
||||||
|
Key* KeyAt(BPoint point);
|
||||||
|
|
||||||
|
BRect Bounds();
|
||||||
|
BSize DefaultKeySize();
|
||||||
|
|
||||||
|
status_t Load(const char* path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum parse_mode {
|
||||||
|
kPairs,
|
||||||
|
kSize,
|
||||||
|
kRowStart,
|
||||||
|
kKeyShape,
|
||||||
|
kKeyCodes
|
||||||
|
};
|
||||||
|
struct parse_state {
|
||||||
|
parse_mode mode;
|
||||||
|
int32 line;
|
||||||
|
};
|
||||||
|
|
||||||
|
void _SetDefault();
|
||||||
|
void _FreeKeys();
|
||||||
|
void _Error(const parse_state& state,
|
||||||
|
const char* reason, ...);
|
||||||
|
void _AddAlternateKeyCode(Key* key, int32 modifier,
|
||||||
|
int32 code);
|
||||||
|
bool _AddKey(const Key& key);
|
||||||
|
void _SkipCommentsAndSpace(parse_state& state,
|
||||||
|
const char*& data);
|
||||||
|
void _Trim(BString& string, bool stripComments);
|
||||||
|
bool _GetPair(const parse_state& state,
|
||||||
|
const char*& data, BString& name,
|
||||||
|
BString& value);
|
||||||
|
bool _AddKeyCodes(const parse_state& state,
|
||||||
|
BPoint& rowLeftTop, Key& key, const char* data,
|
||||||
|
int32& lastCount);
|
||||||
|
bool _GetSize(const parse_state& state, const char* data,
|
||||||
|
float& x, float& y, float* _secondRow = NULL);
|
||||||
|
bool _GetShape(const parse_state& state,
|
||||||
|
const char* data, Key& key);
|
||||||
|
const char* _Delimiter(parse_mode mode);
|
||||||
|
bool _GetTerm(const char*& data, const char* delimiter,
|
||||||
|
BString& term, bool closingBracketAllowed);
|
||||||
|
bool _SubstituteVariables(BString& term,
|
||||||
|
VariableMap& variables, BString& unknown);
|
||||||
|
bool _ParseTerm(const parse_state& state,
|
||||||
|
const char*& data, BString& term,
|
||||||
|
VariableMap& variables);
|
||||||
|
|
||||||
|
status_t _InitFrom(const char* data);
|
||||||
|
|
||||||
|
BString fName;
|
||||||
|
Key* fKeys;
|
||||||
|
int32 fKeyCount;
|
||||||
|
int32 fKeyCapacity;
|
||||||
|
BRect fBounds;
|
||||||
|
BSize fDefaultKeySize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEYBOARD_LAYOUT_H
|
||||||
@@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "KeyboardLayoutView.h"
|
||||||
|
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "Keymap.h"
|
||||||
|
|
||||||
|
|
||||||
|
KeyboardLayoutView::KeyboardLayoutView(const char* name)
|
||||||
|
: BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
|
||||||
|
fKeymap(NULL),
|
||||||
|
fModifiers(0),
|
||||||
|
fDeadKey(0)
|
||||||
|
{
|
||||||
|
fLayout = new KeyboardLayout;
|
||||||
|
memset(fKeyState, 0, sizeof(fKeyState));
|
||||||
|
|
||||||
|
SetEventMask(B_KEYBOARD_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KeyboardLayoutView::~KeyboardLayoutView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::SetKeyboardLayout(KeyboardLayout* layout)
|
||||||
|
{
|
||||||
|
fLayout = layout;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::SetKeymap(Keymap* keymap)
|
||||||
|
{
|
||||||
|
fKeymap = keymap;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::AttachedToWindow()
|
||||||
|
{
|
||||||
|
if (Parent())
|
||||||
|
SetViewColor(Parent()->ViewColor());
|
||||||
|
else
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
|
||||||
|
fFont = *be_plain_font;
|
||||||
|
fSpecialFont = *be_fixed_font;
|
||||||
|
|
||||||
|
font_height fontHeight;
|
||||||
|
fFont.GetHeight(&fontHeight);
|
||||||
|
fFontHeight = fontHeight.ascent + fontHeight.descent;
|
||||||
|
|
||||||
|
FrameResized(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::FrameResized(float width, float height)
|
||||||
|
{
|
||||||
|
float factorX = Bounds().Width() / fLayout->Bounds().Width();
|
||||||
|
float factorY = Bounds().Height() / fLayout->Bounds().Height();
|
||||||
|
|
||||||
|
fFactor = min_c(factorX, factorY);
|
||||||
|
fOffset = BPoint((Bounds().Width() - fLayout->Bounds().Width()
|
||||||
|
* fFactor) / 2,
|
||||||
|
(Bounds().Height() - fLayout->Bounds().Height() * fFactor) / 2);
|
||||||
|
fMaxFontSize = 14;
|
||||||
|
fGap = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
BSize
|
||||||
|
KeyboardLayoutView::MinSize()
|
||||||
|
{
|
||||||
|
// TODO!
|
||||||
|
BSize size(100, 100);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::KeyDown(const char* bytes, int32 numBytes)
|
||||||
|
{
|
||||||
|
_KeyChanged(Window()->CurrentMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::KeyUp(const char* bytes, int32 numBytes)
|
||||||
|
{
|
||||||
|
_KeyChanged(Window()->CurrentMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::MouseDown(BPoint point)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::MouseUp(BPoint point)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::MouseMoved(BPoint point, uint32 transit,
|
||||||
|
const BMessage* dragMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
rgb_color brightColor = {230, 230, 230};
|
||||||
|
rgb_color darkColor = {200, 200, 200};
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fLayout->CountKeys(); i++) {
|
||||||
|
Key* key = fLayout->KeyAt(i);
|
||||||
|
|
||||||
|
BRect rect = _FrameFor(key);
|
||||||
|
rgb_color base = key->dark ? darkColor : brightColor;
|
||||||
|
bool pressed = _IsKeyPressed(key->code);
|
||||||
|
bool special = false;
|
||||||
|
|
||||||
|
char text[32];
|
||||||
|
if (fKeymap != NULL) {
|
||||||
|
_GetKeyLabel(key, text, sizeof(text), special);
|
||||||
|
} else {
|
||||||
|
// Show the key code if there is no keymap
|
||||||
|
snprintf(text, sizeof(text), "%02lx", key->code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (special) {
|
||||||
|
fSpecialFont.SetSize(_FontSizeFor(rect, text) * 0.8);
|
||||||
|
SetFont(&fSpecialFont);
|
||||||
|
} else {
|
||||||
|
fFont.SetSize(_FontSizeFor(rect, text));
|
||||||
|
SetFont(&fFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key->shape == kRectangleKeyShape) {
|
||||||
|
be_control_look->DrawButtonFrame(this, rect, updateRect, base,
|
||||||
|
pressed ? BControlLook::B_ACTIVATED : 0);
|
||||||
|
be_control_look->DrawButtonBackground(this, rect, updateRect,
|
||||||
|
base, pressed ? BControlLook::B_ACTIVATED : 0);
|
||||||
|
|
||||||
|
// TODO: make font size depend on key size!
|
||||||
|
rect.InsetBy(1, 1);
|
||||||
|
|
||||||
|
be_control_look->DrawLabel(this, text, rect, updateRect,
|
||||||
|
base, 0, BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE));
|
||||||
|
} else if (key->shape == kEnterKeyShape) {
|
||||||
|
// TODO: make better!
|
||||||
|
rect.bottom -= 20;
|
||||||
|
be_control_look->DrawButtonBackground(this, rect, updateRect,
|
||||||
|
key->dark ? darkColor : brightColor, 0,
|
||||||
|
BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER
|
||||||
|
| BControlLook::B_TOP_BORDER);
|
||||||
|
|
||||||
|
rect = _FrameFor(key);
|
||||||
|
rect.top += 20;
|
||||||
|
rect.left += 10;
|
||||||
|
be_control_look->DrawButtonBackground(this, rect, updateRect,
|
||||||
|
key->dark ? darkColor : brightColor, 0,
|
||||||
|
BControlLook::B_LEFT_BORDER | BControlLook::B_RIGHT_BORDER
|
||||||
|
| BControlLook::B_BOTTOM_BORDER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case B_UNMAPPED_KEY_DOWN:
|
||||||
|
case B_UNMAPPED_KEY_UP:
|
||||||
|
_KeyChanged(message);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_MODIFIERS_CHANGED:
|
||||||
|
if (message->FindInt32("modifiers", &fModifiers) == B_OK)
|
||||||
|
Invalidate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BView::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
KeyboardLayoutView::_ModifierKeyLabel(const key_map& map, uint32 code)
|
||||||
|
{
|
||||||
|
if (code == map.caps_key)
|
||||||
|
return "CAPS LOCK";
|
||||||
|
if (code == map.scroll_key)
|
||||||
|
return "SCROLL";
|
||||||
|
if (code == map.num_key)
|
||||||
|
return "NUM LOCK";
|
||||||
|
if (code == map.left_shift_key || code == map.right_shift_key)
|
||||||
|
return "SHIFT";
|
||||||
|
if (code == map.left_command_key || code == map.right_command_key)
|
||||||
|
return "COMMAND";
|
||||||
|
if (code == map.left_control_key || code == map.right_control_key)
|
||||||
|
return "CONTROL";
|
||||||
|
if (code == map.left_option_key || code == map.right_option_key)
|
||||||
|
return "OPTION";
|
||||||
|
if (code == map.menu_key)
|
||||||
|
return "MENU";
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
KeyboardLayoutView::_SpecialKeyLabel(const char* bytes, size_t numBytes)
|
||||||
|
{
|
||||||
|
if (numBytes != 1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (bytes[0] == B_ESCAPE)
|
||||||
|
return "ESC";
|
||||||
|
if (bytes[0] == B_TAB)
|
||||||
|
return "\xe2\x86\xb9";
|
||||||
|
if (bytes[0] == B_ENTER)
|
||||||
|
return "\xe2\x86\xb5";
|
||||||
|
if (bytes[0] == B_BACKSPACE)
|
||||||
|
return "back";//\xe2\x86\x92";
|
||||||
|
|
||||||
|
if (bytes[0] == B_INSERT)
|
||||||
|
return "INS";
|
||||||
|
if (bytes[0] == B_DELETE)
|
||||||
|
return "DEL";
|
||||||
|
if (bytes[0] == B_HOME)
|
||||||
|
return "HOME";
|
||||||
|
if (bytes[0] == B_END)
|
||||||
|
return "END";
|
||||||
|
if (bytes[0] == B_PAGE_UP)
|
||||||
|
return "PAGE \xe2\x86\x91";
|
||||||
|
if (bytes[0] == B_PAGE_DOWN)
|
||||||
|
return "PAGE \xe2\x86\x93";
|
||||||
|
|
||||||
|
if (bytes[0] == B_UP_ARROW)
|
||||||
|
return "\xe2\x86\x91";
|
||||||
|
if (bytes[0] == B_LEFT_ARROW)
|
||||||
|
return "\xe2\x86\x90";
|
||||||
|
if (bytes[0] == B_DOWN_ARROW)
|
||||||
|
return "\xe2\x86\x93";
|
||||||
|
if (bytes[0] == B_RIGHT_ARROW)
|
||||||
|
return "\xe2\x86\x92";
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayoutView::_FunctionKeyLabel(const char* bytes, size_t numBytes,
|
||||||
|
char* text, size_t textSize)
|
||||||
|
{
|
||||||
|
if (bytes[0] != B_FUNCTION_KEY)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (bytes[1] >= B_F1_KEY && bytes[1] <= B_F12_KEY) {
|
||||||
|
snprintf(text, textSize, "F%d", bytes[1] + 1 - B_F1_KEY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::_GetKeyLabel(Key* key, char* text, size_t textSize,
|
||||||
|
bool& specialKey)
|
||||||
|
{
|
||||||
|
const key_map& map = fKeymap->Map();
|
||||||
|
specialKey = false;
|
||||||
|
text[0] = '\0';
|
||||||
|
|
||||||
|
const char* modifier = _ModifierKeyLabel(map, key->code);
|
||||||
|
if (modifier != NULL) {
|
||||||
|
strlcpy(text, modifier, textSize);
|
||||||
|
specialKey = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* bytes = NULL;
|
||||||
|
int32 numBytes;
|
||||||
|
fKeymap->GetChars(key->code, fModifiers, fDeadKey, &bytes,
|
||||||
|
&numBytes);
|
||||||
|
if (bytes != NULL) {
|
||||||
|
const char* special = _SpecialKeyLabel(bytes, numBytes);
|
||||||
|
if (special != NULL) {
|
||||||
|
strlcpy(text, special, textSize);
|
||||||
|
specialKey = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_FunctionKeyLabel(bytes, numBytes, text, textSize)) {
|
||||||
|
specialKey = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGlyphs;
|
||||||
|
fFont.GetHasGlyphs(bytes, 1, &hasGlyphs);
|
||||||
|
if (hasGlyphs)
|
||||||
|
strlcpy(text, bytes, sizeof(text));
|
||||||
|
|
||||||
|
delete[] bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
KeyboardLayoutView::_IsKeyPressed(int32 code)
|
||||||
|
{
|
||||||
|
if (code >= 16 * 8)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (fKeyState[code / 8] & (1 << (7 - (code & 7)))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Key*
|
||||||
|
KeyboardLayoutView::_KeyForCode(int32 code)
|
||||||
|
{
|
||||||
|
// TODO: have a lookup array
|
||||||
|
|
||||||
|
for (int32 i = 0; i < fLayout->CountKeys(); i++) {
|
||||||
|
Key* key = fLayout->KeyAt(i);
|
||||||
|
if (key->code == code)
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::_InvalidateKey(int32 code)
|
||||||
|
{
|
||||||
|
Key* key = _KeyForCode(code);
|
||||||
|
if (key != NULL)
|
||||||
|
Invalidate(_FrameFor(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyboardLayoutView::_KeyChanged(BMessage* message)
|
||||||
|
{
|
||||||
|
const uint8* state;
|
||||||
|
ssize_t size;
|
||||||
|
if (message->FindData("states", B_UINT8_TYPE, (const void**)&state, &size)
|
||||||
|
!= B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update key state, and invalidate change keys
|
||||||
|
|
||||||
|
for (int32 i = 0; i < 16; i++) {
|
||||||
|
if (fKeyState[i] != state[i]) {
|
||||||
|
uint8 diff = fKeyState[i] ^ state[i];
|
||||||
|
fKeyState[i] = state[i];
|
||||||
|
|
||||||
|
for (int32 j = 7; diff != 0; j--, diff >>= 1) {
|
||||||
|
if (diff & 1) {
|
||||||
|
_InvalidateKey(i * 8 + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
KeyboardLayoutView::_FrameFor(Key* key)
|
||||||
|
{
|
||||||
|
BRect rect;
|
||||||
|
rect.left = key->frame.left * fFactor;
|
||||||
|
rect.right = (key->frame.right - key->frame.left) * fFactor + rect.left
|
||||||
|
- fGap - 1;
|
||||||
|
rect.top = key->frame.top * fFactor;
|
||||||
|
rect.bottom = (key->frame.bottom - key->frame.top) * fFactor + rect.top
|
||||||
|
- fGap - 1;
|
||||||
|
rect.OffsetBy(fOffset);
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
KeyboardLayoutView::_FontSizeFor(BRect frame, const char* text)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
//float stringWidth = fFont.StringWidth(text);
|
||||||
|
// TODO: take width into account!
|
||||||
|
|
||||||
|
float size = fFont.Size() * (frame.Height() - 6) / fFontHeight;
|
||||||
|
if (size > fMaxFontSize)
|
||||||
|
return fMaxFontSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 10.0f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef KEYBOARD_LAYOUT_VIEW_H
|
||||||
|
#define KEYBOARD_LAYOUT_VIEW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
#include "KeyboardLayout.h"
|
||||||
|
|
||||||
|
class Keymap;
|
||||||
|
|
||||||
|
|
||||||
|
class KeyboardLayoutView : public BView {
|
||||||
|
public:
|
||||||
|
KeyboardLayoutView(const char* name);
|
||||||
|
~KeyboardLayoutView();
|
||||||
|
|
||||||
|
void SetKeyboardLayout(KeyboardLayout* layout);
|
||||||
|
void SetKeymap(Keymap* keymap);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
virtual void FrameResized(float width, float height);
|
||||||
|
// virtual BSize MinSize();
|
||||||
|
|
||||||
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
virtual void KeyUp(const char* bytes, int32 numBytes);
|
||||||
|
virtual void MouseDown(BPoint point);
|
||||||
|
virtual void MouseUp(BPoint point);
|
||||||
|
virtual void MouseMoved(BPoint point, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* _ModifierKeyLabel(const key_map& map, uint32 code);
|
||||||
|
const char* _SpecialKeyLabel(const char* bytes,
|
||||||
|
size_t numBytes);
|
||||||
|
bool _FunctionKeyLabel(const char* bytes,
|
||||||
|
size_t numBytes, char* text, size_t textSize);
|
||||||
|
void _GetKeyLabel(Key* key, char* text, size_t textSize,
|
||||||
|
bool& specialKey);
|
||||||
|
bool _IsKeyPressed(int32 code);
|
||||||
|
Key* _KeyForCode(int32 code);
|
||||||
|
void _InvalidateKey(int32 code);
|
||||||
|
void _KeyChanged(BMessage* message);
|
||||||
|
BRect _FrameFor(Key* key);
|
||||||
|
float _FontSizeFor(BRect frame, const char* text);
|
||||||
|
|
||||||
|
KeyboardLayout* fLayout;
|
||||||
|
Keymap* fKeymap;
|
||||||
|
|
||||||
|
uint8 fKeyState[16];
|
||||||
|
int32 fModifiers;
|
||||||
|
int32 fDeadKey;
|
||||||
|
|
||||||
|
BFont fFont;
|
||||||
|
BFont fSpecialFont;
|
||||||
|
float fFontHeight;
|
||||||
|
float fMaxFontSize;
|
||||||
|
BPoint fOffset;
|
||||||
|
float fFactor;
|
||||||
|
float fGap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEYBOARD_LAYOUT_VIEW_H
|
||||||
Reference in New Issue
Block a user