#include "Keymap.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ByteOrder.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <String.h>
#define CHARS_TABLE_MAXSIZE 10000
extern status_t _restore_key_map_();
const char versionPattern[]
= "Version[[:space:]]+=[[:space:]]+\\([[:digit:]]+\\)";
const char capslockPattern[]
= "CapsLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char scrolllockPattern[]
= "ScrollLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char numlockPattern[]
= "NumLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char lshiftPattern[] = "LShift[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char rshiftPattern[] = "RShift[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char lcommandPattern[]
= "LCommand[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char rcommandPattern[]
= "RCommand[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char lcontrolPattern[]
= "LControl[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char rcontrolPattern[]
= "RControl[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char loptionPattern[]
= "LOption[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char roptionPattern[]
= "ROption[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char menuPattern[] = "Menu[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
const char locksettingsPattern[]
= "LockSettings[[:space:]]+=[[:space:]]+\\([[:alnum:]]*\\)"
"[[:space:]]*\\([[:alnum:]]*\\)"
"[[:space:]]*\\([[:alnum:]]*\\)[[:space:]]*";
const char keyPattern[] = "Key[[:space:]]+\\([[:alnum:]]+\\)[[:space:]]+="
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+";
const char acutePattern[] = "Acute[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
const char gravePattern[] = "Grave[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
const char circumflexPattern[] = "Circumflex[[:space:]]+\\([[:alnum:]]"
"+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
const char diaeresisPattern[] = "Diaeresis[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
const char tildePattern[] = "Tilde[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
"[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
const char acutetabPattern[] = "AcuteTab[[:space:]]+="
"[[:space:]]+\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
const char gravetabPattern[] = "GraveTab[[:space:]]+="
"[[:space:]]+\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
const char circumflextabPattern[] = "CircumflexTab[[:space:]]+="
"[[:space:]]+\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
const char diaeresistabPattern[] = "DiaeresisTab[[:space:]]+="
"[[:space:]]+\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
const char tildetabPattern[] = "TildeTab[[:space:]]+="
"[[:space:]]+\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)"
"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
struct re_pattern_buffer versionBuf;
struct re_pattern_buffer capslockBuf;
struct re_pattern_buffer scrolllockBuf;
struct re_pattern_buffer numlockBuf;
struct re_pattern_buffer lshiftBuf;
struct re_pattern_buffer rshiftBuf;
struct re_pattern_buffer lcommandBuf;
struct re_pattern_buffer rcommandBuf;
struct re_pattern_buffer lcontrolBuf;
struct re_pattern_buffer rcontrolBuf;
struct re_pattern_buffer loptionBuf;
struct re_pattern_buffer roptionBuf;
struct re_pattern_buffer menuBuf;
struct re_pattern_buffer locksettingsBuf;
struct re_pattern_buffer keyBuf;
struct re_pattern_buffer acuteBuf;
struct re_pattern_buffer graveBuf;
struct re_pattern_buffer circumflexBuf;
struct re_pattern_buffer diaeresisBuf;
struct re_pattern_buffer tildeBuf;
struct re_pattern_buffer acutetabBuf;
struct re_pattern_buffer gravetabBuf;
struct re_pattern_buffer circumflextabBuf;
struct re_pattern_buffer diaeresistabBuf;
struct re_pattern_buffer tildetabBuf;
void
dump_map(FILE* file, const char* name, int32* map)
{
fprintf(file, "\t%s:\n\t{\n", name);
for (uint32 i = 0; i < 16; i++) {
fputs("\t\t", file);
for (uint32 j = 0; j < 8; j++) {
fprintf(file, "0x%04" B_PRIx32 ",%s", map[i * 8 + j],
j < 7 ? " " : "");
}
fputs("\n", file);
}
fputs("\t},\n", file);
}
void
dump_keys(FILE* file, const char* name, int32* keys)
{
fprintf(file, "\t%s:\n\t{\n", name);
for (uint32 i = 0; i < 4; i++) {
fprintf(file, "\t\t");
for (uint32 j = 0; j < 8; j++) {
fprintf(file, "0x%04" B_PRIx32 ",%s", keys[i * 8 + j],
j < 7 ? " " : "");
}
fputs("\n", file);
}
fputs("\t},\n", file);
}
Keymap::Keymap()
{
}
Keymap::~Keymap()
{
}
status_t
Keymap::LoadSource(const char* name)
{
FILE* file = fopen(name, "r");
if (file == NULL)
return errno;
status_t status = LoadSource(file);
fclose(file);
return status;
}
status_t
Keymap::LoadSource(FILE* file)
{
reg_syntax_t syntax = RE_CHAR_CLASSES;
re_set_syntax(syntax);
const char* error = NULL;
error = re_compile_pattern(versionPattern, strlen(versionPattern),
&versionBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(capslockPattern, strlen(capslockPattern),
&capslockBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(scrolllockPattern, strlen(scrolllockPattern),
&scrolllockBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(numlockPattern, strlen(numlockPattern),
&numlockBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(lshiftPattern, strlen(lshiftPattern),
&lshiftBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(rshiftPattern, strlen(rshiftPattern),
&rshiftBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(lcommandPattern, strlen(lcommandPattern),
&lcommandBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(rcommandPattern, strlen(rcommandPattern),
&rcommandBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(lcontrolPattern, strlen(lcontrolPattern),
&lcontrolBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(rcontrolPattern, strlen(rcontrolPattern),
&rcontrolBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(loptionPattern, strlen(loptionPattern),
&loptionBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(roptionPattern, strlen(roptionPattern),
&roptionBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(menuPattern, strlen(menuPattern), &menuBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(locksettingsPattern,
strlen(locksettingsPattern), &locksettingsBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(keyPattern, strlen(keyPattern), &keyBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(acutePattern, strlen(acutePattern), ´Buf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(gravePattern, strlen(gravePattern), &graveBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(circumflexPattern, strlen(circumflexPattern),
&circumflexBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(diaeresisPattern, strlen(diaeresisPattern),
&diaeresisBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(tildePattern, strlen(tildePattern), &tildeBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(acutetabPattern, strlen(acutetabPattern),
´tabBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(gravetabPattern, strlen(gravetabPattern),
&gravetabBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(circumflextabPattern,
strlen(circumflextabPattern), &circumflextabBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(diaeresistabPattern,
strlen(diaeresistabPattern), &diaeresistabBuf);
if (error)
fputs(error, stderr);
error = re_compile_pattern(tildetabPattern, strlen(tildetabPattern),
&tildetabBuf);
if (error)
fputs(error, stderr);
delete[] fChars;
fChars = new char[CHARS_TABLE_MAXSIZE];
fCharsSize = CHARS_TABLE_MAXSIZE;
int offset = 0;
int acuteOffset = 0;
int graveOffset = 0;
int circumflexOffset = 0;
int diaeresisOffset = 0;
int tildeOffset = 0;
int32* maps[] = {
fKeys.normal_map,
fKeys.shift_map,
fKeys.control_map,
fKeys.option_map,
fKeys.option_shift_map,
fKeys.caps_map,
fKeys.caps_shift_map,
fKeys.option_caps_map,
fKeys.option_caps_shift_map
};
char buffer[1024];
while (fgets(buffer, sizeof(buffer) - 1, file) != NULL) {
if (buffer[0] == '#' || buffer[0] == '\n')
continue;
size_t length = strlen(buffer);
struct re_registers regs;
if (re_search(&versionBuf, buffer, length, 0, length, ®s) >= 0) {
sscanf(buffer + regs.start[1], "%" B_SCNu32, &fKeys.version);
} else if (re_search(&capslockBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.caps_key);
} else if (re_search(&scrolllockBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.scroll_key);
} else if (re_search(&numlockBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.num_key);
} else if (re_search(&lshiftBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.left_shift_key);
} else if (re_search(&rshiftBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.right_shift_key);
} else if (re_search(&lcommandBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.left_command_key);
} else if (re_search(&rcommandBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.right_command_key);
} else if (re_search(&lcontrolBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.left_control_key);
} else if (re_search(&rcontrolBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.right_control_key);
} else if (re_search(&loptionBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.left_option_key);
} else if (re_search(&roptionBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
&fKeys.right_option_key);
} else if (re_search(&menuBuf, buffer, length, 0, length, ®s)
>= 0) {
sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.menu_key);
} else if (re_search(&locksettingsBuf, buffer, length, 0, length, ®s)
>= 0) {
fKeys.lock_settings = 0;
for (int32 i = 1; i <= 3; i++) {
const char* start = buffer + regs.start[i];
length = regs.end[i] - regs.start[i];
if (length == 0)
break;
if (!strncmp(start, "CapsLock", length))
fKeys.lock_settings |= B_CAPS_LOCK;
else if (!strncmp(start, "NumLock", length))
fKeys.lock_settings |= B_NUM_LOCK;
else if (!strncmp(start, "ScrollLock", length))
fKeys.lock_settings |= B_SCROLL_LOCK;
}
} else if (re_search(&keyBuf, buffer, length, 0, length, ®s)
>= 0) {
uint32 keyCode;
if (sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &keyCode) > 0) {
for (int i = 2; i <= 10; i++) {
maps[i - 2][keyCode] = offset;
_ComputeChars(buffer, regs, i, offset);
}
}
} else if (re_search(´Buf, buffer, length, 0, length, ®s)
>= 0) {
for (int i = 1; i <= 2; i++) {
fKeys.acute_dead_key[acuteOffset++] = offset;
_ComputeChars(buffer, regs, i, offset);
}
} else if (re_search(&graveBuf, buffer, length, 0, length, ®s)
>= 0) {
for (int i = 1; i <= 2; i++) {
fKeys.grave_dead_key[graveOffset++] = offset;
_ComputeChars(buffer, regs, i, offset);
}
} else if (re_search(&circumflexBuf, buffer, length, 0, length, ®s)
>= 0) {
for (int i = 1; i <= 2; i++) {
fKeys.circumflex_dead_key[circumflexOffset++] = offset;
_ComputeChars(buffer, regs, i, offset);
}
} else if (re_search(&diaeresisBuf, buffer, length, 0, length, ®s)
>= 0) {
for (int i = 1; i <= 2; i++) {
fKeys.dieresis_dead_key[diaeresisOffset++] = offset;
_ComputeChars(buffer, regs, i, offset);
}
} else if (re_search(&tildeBuf, buffer, length, 0, length, ®s) >= 0) {
for (int i = 1; i <= 2; i++) {
fKeys.tilde_dead_key[tildeOffset++] = offset;
_ComputeChars(buffer, regs, i, offset);
}
} else if (re_search(´tabBuf, buffer, length, 0, length, ®s)
>= 0) {
_ComputeTables(buffer, regs, fKeys.acute_tables);
} else if (re_search(&gravetabBuf, buffer, length, 0, length, ®s)
>= 0) {
_ComputeTables(buffer, regs, fKeys.grave_tables);
} else if (re_search(&circumflextabBuf, buffer, length, 0, length, ®s)
>= 0) {
_ComputeTables(buffer, regs, fKeys.circumflex_tables);
} else if (re_search(&diaeresistabBuf, buffer, length, 0, length, ®s)
>= 0) {
_ComputeTables(buffer, regs, fKeys.dieresis_tables);
} else if (re_search(&tildetabBuf, buffer, length, 0, length, ®s)
>= 0) {
_ComputeTables(buffer, regs, fKeys.tilde_tables);
}
}
fCharsSize = offset;
if (fKeys.version != 3)
return KEYMAP_ERROR_UNKNOWN_VERSION;
return B_OK;
}
status_t
Keymap::SaveAsCurrent()
{
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
BPath path;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
if (status != B_OK)
return status;
path.Append("Key_map");
status = Save(path.Path());
if (status != B_OK)
return status;
Use();
return B_OK;
#else
fprintf(stderr, "Unsupported operation on this platform!\n");
exit(1);
#endif
}
status_t
Keymap::Save(const char* name)
{
BFile file;
status_t status = file.SetTo(name,
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
if (status != B_OK)
return status;
for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]);
}
ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys));
for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
}
if (bytesWritten < (ssize_t)sizeof(fKeys))
return B_ERROR;
if (bytesWritten < B_OK)
return bytesWritten;
uint32 charSize = B_HOST_TO_BENDIAN_INT32(fCharsSize);
bytesWritten = file.Write(&charSize, sizeof(uint32));
if (bytesWritten < (ssize_t)sizeof(uint32))
return B_ERROR;
if (bytesWritten < B_OK)
return bytesWritten;
bytesWritten = file.Write(fChars, fCharsSize);
if (bytesWritten < (ssize_t)fCharsSize)
return B_ERROR;
if (bytesWritten < B_OK)
return bytesWritten;
return B_OK;
}
status_t
Keymap::SaveAsSource(const char* name)
{
FILE* file = fopen(name, "w");
if (file == NULL)
return errno;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
text_run_array* textRuns;
_SaveSourceText(file, &textRuns);
if (textRuns != NULL) {
int32 dataSize;
void* data = BTextView::FlattenRunArray(textRuns, &dataSize);
if (data != NULL) {
BNode node(name);
node.WriteAttr("styles", B_RAW_TYPE, 0, data, dataSize);
free(data);
}
BTextView::FreeRunArray(textRuns);
}
#else
_SaveSourceText(file);
#endif
fclose(file);
return B_OK;
}
status_t
Keymap::SaveAsSource(FILE* file)
{
_SaveSourceText(file);
return B_OK;
}
status_t
Keymap::SaveAsCppHeader(const char* fileName, const char* mapName)
{
BString name = mapName;
int32 index = name.FindLast('/');
if (index > 0)
name.Remove(0, index + 1);
index = name.FindLast('.');
if (index > 0)
name.Truncate(index);
FILE* file = fopen(fileName, "w");
if (file == NULL)
return errno;
fputs("/*\n"
" * Haiku Default System Keymap\n"
" * This file is automatically generated. Do not edit!\n"
" */\n", file);
fputs("#ifndef\t_SYSTEM_KEYMAP_H\n"
"#define\t_SYSTEM_KEYMAP_H\n\n\n", file);
fputs("#include <InterfaceDefs.h>\n\n\n", file);
fputs("#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n\n", file);
fprintf(file, "const char *kSystemKeymapName = \"%s\";\n\n", name.String());
fputs("const key_map kSystemKeymap = {\n", file);
fprintf(file, "\tversion:%" B_PRIu32 ",\n", fKeys.version);
fprintf(file, "\tcaps_key:0x%" B_PRIx32 ",\n", fKeys.caps_key);
fprintf(file, "\tscroll_key:0x%" B_PRIx32 ",\n", fKeys.scroll_key);
fprintf(file, "\tnum_key:0x%" B_PRIx32 ",\n", fKeys.num_key);
fprintf(file, "\tleft_shift_key:0x%" B_PRIx32 ",\n", fKeys.left_shift_key);
fprintf(file, "\tright_shift_key:0x%" B_PRIx32 ",\n",
fKeys.right_shift_key);
fprintf(file, "\tleft_command_key:0x%" B_PRIx32 ",\n",
fKeys.left_command_key);
fprintf(file, "\tright_command_key:0x%" B_PRIx32 ",\n",
fKeys.right_command_key);
fprintf(file, "\tleft_control_key:0x%" B_PRIx32 ",\n",
fKeys.left_control_key);
fprintf(file, "\tright_control_key:0x%" B_PRIx32 ",\n",
fKeys.right_control_key);
fprintf(file, "\tleft_option_key:0x%" B_PRIx32 ",\n",
fKeys.left_option_key);
fprintf(file, "\tright_option_key:0x%" B_PRIx32 ",\n",
fKeys.right_option_key);
fprintf(file, "\tmenu_key:0x%" B_PRIx32 ",\n", fKeys.menu_key);
fprintf(file, "\tlock_settings:0x%" B_PRIx32 ",\n", fKeys.lock_settings);
dump_map(file, "control_map", fKeys.control_map);
dump_map(file, "option_caps_shift_map", fKeys.option_caps_shift_map);
dump_map(file, "option_caps_map", fKeys.option_caps_map);
dump_map(file, "option_shift_map", fKeys.option_shift_map);
dump_map(file, "option_map", fKeys.option_map);
dump_map(file, "caps_shift_map", fKeys.caps_shift_map);
dump_map(file, "caps_map", fKeys.caps_map);
dump_map(file, "shift_map", fKeys.shift_map);
dump_map(file, "normal_map", fKeys.normal_map);
dump_keys(file, "acute_dead_key", fKeys.acute_dead_key);
dump_keys(file, "grave_dead_key", fKeys.grave_dead_key);
dump_keys(file, "circumflex_dead_key", fKeys.circumflex_dead_key);
dump_keys(file, "dieresis_dead_key", fKeys.dieresis_dead_key);
dump_keys(file, "tilde_dead_key", fKeys.tilde_dead_key);
fprintf(file, "\tacute_tables:0x%" B_PRIx32 ",\n", fKeys.acute_tables);
fprintf(file, "\tgrave_tables:0x%" B_PRIx32 ",\n", fKeys.grave_tables);
fprintf(file, "\tcircumflex_tables:0x%" B_PRIx32 ",\n",
fKeys.circumflex_tables);
fprintf(file, "\tdieresis_tables:0x%" B_PRIx32 ",\n",
fKeys.dieresis_tables);
fprintf(file, "\ttilde_tables:0x%" B_PRIx32 ",\n", fKeys.tilde_tables);
fputs("};\n\n", file);
fputs("const uchar kSystemKeyChars[] = {\n", file);
for (uint32 i = 0; i < fCharsSize; i++) {
if (i % 10 == 0) {
if (i > 0)
fputs("\n", file);
fputs("\t", file);
} else
fputs(" ", file);
fprintf(file, "0x%02x,", (uint8)fChars[i]);
}
fputs("\n};\n\n", file);
fprintf(file, "const uint32 kSystemKeyCharsSize = %" B_PRIu32 ";\n\n",
fCharsSize);
fputs("#ifdef __cplusplus\n"
"}\n"
"#endif\n\n"
"#endif\t// _SYSTEM_KEYMAP_H\n", file);
fclose(file);
return B_OK;
}
status_t
Keymap::Use()
{
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
return _restore_key_map_();
#else
fprintf(stderr, "Unsupported operation on this platform!\n");
exit(1);
#endif
}
void
Keymap::RestoreSystemDefault()
{
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
# ifdef find_directory
# undef find_directory
# endif
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return;
path.Append("Key_map");
BEntry entry(path.Path());
entry.Remove();
_restore_key_map_();
#else
fprintf(stderr, "Unsupported operation on this platform!\n");
exit(1);
#endif
}
bool
Keymap::GetKey(const char* chars, int32 offset, char* buffer, size_t bufferSize)
{
uint8 size = (uint8)chars[offset++];
char string[1024];
switch (size) {
case 0:
strlcpy(buffer, "''", bufferSize);
return false;
case 1:
if ((uint8)chars[offset] < 0x20 || (uint8)chars[offset] > 0x7e)
sprintf(string, "0x%02x", (uint8)chars[offset]);
else {
sprintf(string, "'%s%c'",
(chars[offset] == '\\' || chars[offset] == '\'') ? "\\" : "",
chars[offset]);
}
break;
default:
sprintf(string, "0x");
for (int i = 0; i < size; i++) {
sprintf(string + 2 * (i + 1), "%02x", (uint8)chars[offset + i]);
}
break;
}
strlcpy(buffer, string, bufferSize);
return true;
}
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
void
Keymap::_SaveSourceText(FILE* file, text_run_array** _textRuns)
{
text_run_array* runs = NULL;
if (_textRuns != NULL) {
runs = BTextView::AllocRunArray(8);
*_textRuns = runs;
}
#else
void
Keymap::_SaveSourceText(FILE* file)
{
#endif
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
static const rgb_color kCommentColor = (rgb_color){200, 92, 92, 255};
static const rgb_color kTextColor = (rgb_color){0, 0, 0, 255};
BFont font = *be_fixed_font;
if (runs != NULL) {
runs->runs[0].offset = 0;
runs->runs[0].font = font;
runs->runs[0].color = kCommentColor;
}
#endif
int bytes = fprintf(file, "#!/bin/keymap -s\n"
"#\n"
"#\tRaw key numbering for 102-key keyboard...\n");
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[1].offset = bytes;
runs->runs[1].font = font;
runs->runs[1].font.SetSize(9);
runs->runs[1].color = kCommentColor;
}
#endif
bytes += fprintf(file, "# [sys] [brk]\n"
"# 0x7e 0x7f\n"
"# [esc] [ f1] [ f2] [ f3] [ f4] [ f5] [ f6] [ f7] [ f8] [ f9] [f10] [f11] [f12] [prn] [scr] [pau]\n"
"# 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 K E Y P A D K E Y S\n"
"#\n"
"# [ ` ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] [ - ] [ = ] [ bck ] [ins] [hme] [pup] [num] [ / ] [ * ] [ - ]\n"
"# 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x21 0x22 0x23 0x24 0x25\n"
"#\n"
"# [ tab ] [ q ] [ w ] [ e ] [ r ] [ t ] [ y ] [ u ] [ i ] [ o ] [ p ] [ [ ] [ ] ] [ \\ ] [del] [end] [pdn] [ 7 ] [ 8 ] [ 9 ] [ + ]\n"
"# 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a\n"
"#\n"
"# [ caps ] [ a ] [ s ] [ d ] [ f ] [ g ] [ h ] [ j ] [ k ] [ l ] [ ; ] [ ' ] [ enter ] [ 4 ] [ 5 ] [ 6 ]\n"
"# 0x3b 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a\n"
"#\n"
"# [shft] [ \\ ] [ z ] [ x ] [ c ] [ v ] [ b ] [ n ] [ m ] [ , ] [ . ] [ / ] [ shift ] [ up] [ 1 ] [ 2 ] [ 3 ] [ent]\n"
"# 0x4b 0x69 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b\n"
"#\n"
"# [ ctrl ] [ cmd ] [ space ] [ cmd ] [ ctrl ] [lft] [dwn] [rgt] [ 0 ] [ . ]\n"
"# 0x5c 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65\n");
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[2].offset = bytes;
runs->runs[2].font = font;
runs->runs[2].color = kCommentColor;
}
#endif
bytes += fprintf(file, "#\n"
"#\tNOTE: Key 0x69 does not exist on US keyboards\n"
"#\tNOTE: On a Microsoft Natural Keyboard:\n"
"#\t\t\tleft option = 0x66\n"
"#\t\t\tright option = 0x67\n"
"#\t\t\tmenu key = 0x68\n"
"#\tNOTE: On an Apple Extended Keyboard:\n"
"#\t\t\tleft option = 0x66\n"
"#\t\t\tright option = 0x67\n"
"#\t\t\tkeypad '=' = 0x6a\n");
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[3].offset = bytes;
runs->runs[3].font = *be_fixed_font;
runs->runs[3].color = kTextColor;
}
#endif
bytes += fprintf(file, "Version = %" B_PRIu32 "\n"
"CapsLock = 0x%02" B_PRIx32 "\n"
"ScrollLock = 0x%02" B_PRIx32 "\n"
"NumLock = 0x%02" B_PRIx32 "\n"
"LShift = 0x%02" B_PRIx32 "\n"
"RShift = 0x%02" B_PRIx32 "\n"
"LCommand = 0x%02" B_PRIx32 "\n"
"RCommand = 0x%02" B_PRIx32 "\n"
"LControl = 0x%02" B_PRIx32 "\n"
"RControl = 0x%02" B_PRIx32 "\n"
"LOption = 0x%02" B_PRIx32 "\n"
"ROption = 0x%02" B_PRIx32 "\n"
"Menu = 0x%02" B_PRIx32 "\n",
fKeys.version, fKeys.caps_key, fKeys.scroll_key, fKeys.num_key,
fKeys.left_shift_key, fKeys.right_shift_key,
fKeys.left_command_key, fKeys.right_command_key,
fKeys.left_control_key, fKeys.right_control_key,
fKeys.left_option_key, fKeys.right_option_key, fKeys.menu_key);
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[4].offset = bytes;
runs->runs[4].font = *be_fixed_font;
runs->runs[4].color = kCommentColor;
}
#endif
bytes += fprintf(file, "#\n"
"# Lock settings\n"
"# To set NumLock, do the following:\n"
"# LockSettings = NumLock\n"
"#\n"
"# To set everything, do the following:\n"
"# LockSettings = CapsLock NumLock ScrollLock\n"
"#\n");
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[5].offset = bytes;
runs->runs[5].font = *be_fixed_font;
runs->runs[5].color = kTextColor;
}
#endif
bytes += fprintf(file, "LockSettings = ");
if ((fKeys.lock_settings & B_CAPS_LOCK) != 0)
bytes += fprintf(file, "CapsLock ");
if ((fKeys.lock_settings & B_NUM_LOCK) != 0)
bytes += fprintf(file, "NumLock ");
if ((fKeys.lock_settings & B_SCROLL_LOCK) != 0)
bytes += fprintf(file, "ScrollLock ");
bytes += fprintf(file, "\n");
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[6].offset = bytes;
runs->runs[6].font = *be_fixed_font;
runs->runs[6].color = kCommentColor;
}
#endif
bytes += fputs("# Legend:\n"
"# n = Normal\n"
"# s = Shift\n"
"# c = Control\n"
"# C = CapsLock\n"
"# o = Option\n"
"# Key n s c o os "
"C Cs Co Cos \n", file);
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (runs != NULL) {
runs->runs[7].offset = bytes;
runs->runs[7].font = *be_fixed_font;
runs->runs[7].color = kTextColor;
}
#endif
for (int i = 0; i < 128; i++) {
char normalKey[32];
char shiftKey[32];
char controlKey[32];
char optionKey[32];
char optionShiftKey[32];
char capsKey[32];
char capsShiftKey[32];
char optionCapsKey[32];
char optionCapsShiftKey[32];
GetKey(fChars, fKeys.normal_map[i], normalKey, 32);
GetKey(fChars, fKeys.shift_map[i], shiftKey, 32);
GetKey(fChars, fKeys.control_map[i], controlKey, 32);
GetKey(fChars, fKeys.option_map[i], optionKey, 32);
GetKey(fChars, fKeys.option_shift_map[i], optionShiftKey, 32);
GetKey(fChars, fKeys.caps_map[i], capsKey, 32);
GetKey(fChars, fKeys.caps_shift_map[i], capsShiftKey, 32);
GetKey(fChars, fKeys.option_caps_map[i], optionCapsKey, 32);
GetKey(fChars, fKeys.option_caps_shift_map[i], optionCapsShiftKey, 32);
fprintf(file,
"Key 0x%02x = %-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s\n", i,
normalKey, shiftKey, controlKey, optionKey, optionShiftKey,
capsKey, capsShiftKey, optionCapsKey, optionCapsShiftKey);
}
int32* deadOffsets[] = {
fKeys.acute_dead_key,
fKeys.grave_dead_key,
fKeys.circumflex_dead_key,
fKeys.dieresis_dead_key,
fKeys.tilde_dead_key
};
char labels[][12] = {
"Acute",
"Grave",
"Circumflex",
"Diaeresis",
"Tilde"
};
uint32 deadTables[] = {
fKeys.acute_tables,
fKeys.grave_tables,
fKeys.circumflex_tables,
fKeys.dieresis_tables,
fKeys.tilde_tables
};
for (int i = 0; i < 5; i++) {
for (int deadIndex = 0; deadIndex < 32; deadIndex++) {
char deadKey[32];
char secondKey[32];
if (!GetKey(fChars, deadOffsets[i][deadIndex++], deadKey, 32))
break;
GetKey(fChars, deadOffsets[i][deadIndex], secondKey, 32);
fprintf(file, "%s %-9s = %-9s\n", labels[i], deadKey, secondKey);
}
fprintf(file, "%sTab = ", labels[i]);
if ((deadTables[i] & B_NORMAL_TABLE) != 0)
fputs("Normal ", file);
if ((deadTables[i] & B_SHIFT_TABLE) != 0)
fputs("Shift ", file);
if ((deadTables[i] & B_CONTROL_TABLE) != 0)
fputs("Control ", file);
if ((deadTables[i] & B_OPTION_TABLE) != 0)
fputs("Option ", file);
if ((deadTables[i] & B_OPTION_SHIFT_TABLE) != 0)
fputs("Option-Shift ", file);
if ((deadTables[i] & B_CAPS_TABLE) != 0)
fputs("CapsLock ", file);
if ((deadTables[i] & B_CAPS_SHIFT_TABLE) != 0)
fputs("CapsLock-Shift ", file);
if ((deadTables[i] & B_OPTION_CAPS_TABLE) != 0)
fputs("CapsLock-Option ", file);
if ((deadTables[i] & B_OPTION_CAPS_SHIFT_TABLE) != 0)
fputs("CapsLock-Option-Shift ", file);
fputs("\n", file);
}
}
void
Keymap::_ComputeChars(const char* buffer, struct re_registers& regs, int i,
int& offset)
{
char* current = &fChars[offset + 1];
char hexChars[12];
uint32 length = 0;
if (strncmp(buffer + regs.start[i], "''", regs.end[i] - regs.start[i])
== 0) {
length = 0;
} else if (sscanf(buffer + regs.start[i], "'%s'", current) > 0) {
if (current[0] == '\\')
current[0] = current[1];
else if (current[0] == '\'')
current[0] = ' ';
length = 1;
} else if (sscanf(buffer + regs.start[i], "0x%s", hexChars) > 0) {
length = strlen(hexChars) / 2;
for (uint32 j = 0; j < length; j++)
sscanf(hexChars + 2*j, "%02hhx", current + j);
}
fChars[offset] = length;
offset += length + 1;
}
void
Keymap::_ComputeTables(const char* buffer, struct re_registers& regs,
uint32& table)
{
for (int32 i = 1; i <= 9; i++) {
int32 length = regs.end[i] - regs.start[i];
if (length <= 0)
break;
const char* start = buffer + regs.start[i];
if (strncmp(start, "Normal", length) == 0)
table |= B_NORMAL_TABLE;
else if (strncmp(start, "Shift", length) == 0)
table |= B_SHIFT_TABLE;
else if (strncmp(start, "Control", length) == 0)
table |= B_CONTROL_TABLE;
else if (strncmp(start, "Option", length) == 0)
table |= B_OPTION_TABLE;
else if (strncmp(start, "Option-Shift", length) == 0)
table |= B_OPTION_SHIFT_TABLE;
else if (strncmp(start, "CapsLock", length) == 0)
table |= B_CAPS_TABLE;
else if (strncmp(start, "CapsLock-Shift", length) == 0)
table |= B_CAPS_SHIFT_TABLE;
else if (strncmp(start, "CapsLock-Option", length) == 0)
table |= B_OPTION_CAPS_TABLE;
else if (strncmp(start, "CapsLock-Option-Shift", length) == 0)
table |= B_OPTION_CAPS_SHIFT_TABLE;
}
}