* Added support for selecting the dead key trigger characters from a menubar,

offering two choices for acute and diaeresis as well as allowing to switch
  off each dead key completely.
* moved the textview on a line of its own such that the dead key menu and
  the modifier-switching button live together on one line
* added enum dead_key_index and used it at a couple of places instead of
  having to use the magic numbers 1-5
* refactored the actual updating of the fChars buffer from SetKey() into
  _SetChars(), which is now being invoked by SetDeadKeyTrigger(), too

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30718 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe
2009-05-12 18:31:17 +00:00
parent 4d8f5338bd
commit 83936c1c26
4 changed files with 343 additions and 53 deletions
+140 -52
View File
@@ -446,6 +446,78 @@ Keymap::SetDeadKeyEnabled(uint32 keyCode, uint32 modifiers, bool enabled)
}
/*! Returns the trigger character string that is currently set for the dead
key with the given index (which is 1..5).
*/
void
Keymap::GetDeadKeyTrigger(dead_key_index deadKeyIndex, BString& outTrigger)
{
outTrigger = "";
if (deadKeyIndex < 1 || deadKeyIndex > 5)
return;
int32 deadOffsets[] = {
fKeys.acute_dead_key[1],
fKeys.grave_dead_key[1],
fKeys.circumflex_dead_key[1],
fKeys.dieresis_dead_key[1],
fKeys.tilde_dead_key[1]
};
int32 offset = deadOffsets[deadKeyIndex - 1];
if (offset < 0 || offset >= (int32)fCharsSize)
return;
uint32 deadNumBytes = fChars[offset];
if (!deadNumBytes)
return;
outTrigger.SetTo(&fChars[offset + 1], deadNumBytes);
}
/*! Sets the trigger character string that shall be used for the dead key
with the given index (which is 1..5).
*/
void
Keymap::SetDeadKeyTrigger(dead_key_index deadKeyIndex, const BString& trigger)
{
if (deadKeyIndex < 1 || deadKeyIndex > 5)
return;
int32 deadOffsets[] = {
fKeys.acute_dead_key[1],
fKeys.grave_dead_key[1],
fKeys.circumflex_dead_key[1],
fKeys.dieresis_dead_key[1],
fKeys.tilde_dead_key[1]
};
int32 offset = deadOffsets[deadKeyIndex - 1];
if (offset < 0 || offset >= (int32)fCharsSize)
return;
if (_SetChars(offset, trigger.String(), trigger.Length())) {
// reset modifier table such that new dead key is enabled wherever
// it is available
uint32* deadTables[] = {
&fKeys.acute_tables,
&fKeys.grave_tables,
&fKeys.circumflex_tables,
&fKeys.dieresis_tables,
&fKeys.tilde_tables
};
*deadTables[deadKeyIndex - 1]
= B_CONTROL_TABLE | B_OPTION_CAPS_SHIFT_TABLE | B_OPTION_CAPS_TABLE
| B_OPTION_SHIFT_TABLE | B_OPTION_TABLE | B_CAPS_SHIFT_TABLE
| B_CAPS_TABLE | B_SHIFT_TABLE | B_NORMAL_TABLE;
if (fModificationMessage != NULL)
fTarget.SendMessage(fModificationMessage);
}
}
//! Get the char for a key given modifiers and active dead key
void
Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey,
@@ -487,11 +559,21 @@ Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey,
// here we take an potential active dead key
int32 *deadKey;
switch (activeDeadKey) {
case 1: deadKey = fKeys.acute_dead_key; break;
case 2: deadKey = fKeys.grave_dead_key; break;
case 3: deadKey = fKeys.circumflex_dead_key; break;
case 4: deadKey = fKeys.dieresis_dead_key; break;
case 5: deadKey = fKeys.tilde_dead_key; break;
case kDeadKeyAcute:
deadKey = fKeys.acute_dead_key;
break;
case kDeadKeyGrave:
deadKey = fKeys.grave_dead_key;
break;
case kDeadKeyCircumflex:
deadKey = fKeys.circumflex_dead_key;
break;
case kDeadKeyDiaeresis:
deadKey = fKeys.dieresis_dead_key;
break;
case kDeadKeyTilde:
deadKey = fKeys.tilde_dead_key;
break;
default:
{
// if not dead, we copy and return the char
@@ -556,54 +638,10 @@ Keymap::SetKey(uint32 keyCode, uint32 modifiers, int8 deadKey,
if (numBytes > 6)
return;
int32 oldNumBytes = fChars[offset];
if (oldNumBytes == numBytes
&& !memcmp(&fChars[offset + 1], bytes, numBytes)) {
// nothing to do
return;
if (_SetChars(offset, bytes, numBytes)) {
if (fModificationMessage != NULL)
fTarget.SendMessage(fModificationMessage);
}
// TODO: handle dead keys!
int32 diff = numBytes - oldNumBytes;
if (diff != 0) {
fCharsSize += diff;
if (diff > 0) {
// make space for the new data
char* chars = new(std::nothrow) char[fCharsSize];
if (chars != NULL) {
memcpy(chars, fChars, offset + oldNumBytes + 1);
memcpy(&chars[offset + 1 + numBytes],
&fChars[offset + 1 + oldNumBytes],
fCharsSize - 2 - offset - diff);
delete[] fChars;
fChars = chars;
} else
return;
} else if (diff < 0) {
// shrink table
memmove(&fChars[offset + numBytes], &fChars[offset + oldNumBytes],
fCharsSize - offset - 2 - diff);
}
// update offsets
int32* data = fKeys.control_map;
int32 size = sizeof(fKeys.control_map) / 4 * 9
+ sizeof(fKeys.acute_dead_key) / 4 * 5;
for (int32 i = 0; i < size; i++) {
if (data[i] > offset)
data[i] += diff;
}
}
memcpy(&fChars[offset + 1], bytes, numBytes);
fChars[offset] = numBytes;
if (fModificationMessage != NULL)
fTarget.SendMessage(fModificationMessage);
}
@@ -693,6 +731,56 @@ Keymap::_Offset(uint32 keyCode, uint32 modifiers, uint32* _table)
}
bool
Keymap::_SetChars(int32 offset, const char* bytes, int32 numBytes)
{
int32 oldNumBytes = fChars[offset];
if (oldNumBytes == numBytes
&& !memcmp(&fChars[offset + 1], bytes, numBytes)) {
// nothing to do
return false;
}
int32 diff = numBytes - oldNumBytes;
if (diff != 0) {
fCharsSize += diff;
if (diff > 0) {
// make space for the new data
char* chars = new(std::nothrow) char[fCharsSize];
if (chars != NULL) {
memcpy(chars, fChars, offset + oldNumBytes + 1);
memcpy(&chars[offset + 1 + numBytes],
&fChars[offset + 1 + oldNumBytes],
fCharsSize - 2 - offset - diff);
delete[] fChars;
fChars = chars;
} else
return false;
} else if (diff < 0) {
// shrink table
memmove(&fChars[offset + numBytes], &fChars[offset + oldNumBytes],
fCharsSize - offset - 2 - diff);
}
// update offsets
int32* data = fKeys.control_map;
int32 size = sizeof(fKeys.control_map) / 4 * 9
+ sizeof(fKeys.acute_dead_key) / 4 * 5;
for (int32 i = 0; i < size; i++) {
if (data[i] > offset)
data[i] += diff;
}
}
memcpy(&fChars[offset + 1], bytes, numBytes);
fChars[offset] = numBytes;
return true;
}
uint8
Keymap::_GetDeadKeyIndex(int32 offset)
{
+17
View File
@@ -13,6 +13,16 @@
#include <InterfaceDefs.h>
#include <Entry.h>
#include <Messenger.h>
#include <String.h>
enum dead_key_index {
kDeadKeyAcute = 1,
kDeadKeyGrave,
kDeadKeyCircumflex,
kDeadKeyDiaeresis,
kDeadKeyTilde
};
class Keymap {
@@ -39,6 +49,11 @@ public:
uint8 activeDeadKey);
void SetDeadKeyEnabled(uint32 keyCode, uint32 modifiers,
bool enabled);
void GetDeadKeyTrigger(dead_key_index deadKeyIndex,
BString& outTrigger);
void SetDeadKeyTrigger(dead_key_index deadKeyIndex,
const BString& trigger);
void GetChars(uint32 keyCode, uint32 modifiers,
uint8 activeDeadKey, char** chars,
int32* numBytes);
@@ -57,6 +72,8 @@ public:
private:
int32 _Offset(uint32 keyCode, uint32 modifiers,
uint32* _table = NULL);
bool _SetChars(int32 offset, const char* bytes,
int32 numBytes);
uint8 _GetDeadKeyIndex(int32 offset);
char* fChars;
+177 -1
View File
@@ -51,6 +51,14 @@ static const uint32 kMsgUseKeymap = 'UkyM';
static const uint32 kMsgRevertKeymap = 'Rvrt';
static const uint32 kMsgKeymapUpdated = 'upkM';
static const uint32 kMsgDeadKeyAcuteChanged = 'dkAc';
static const uint32 kMsgDeadKeyCircumflexChanged = 'dkCc';
static const uint32 kMsgDeadKeyDiaeresisChanged = 'dkDc';
static const uint32 kMsgDeadKeyGraveChanged = 'dkGc';
static const uint32 kMsgDeadKeyTildeChanged = 'dkTc';
static const char* kDeadKeyTriggerNone = "<none>";
KeymapWindow::KeymapWindow()
: BWindow(BRect(80, 50, 880, 380), "Keymap", B_TITLED_WINDOW,
@@ -80,8 +88,10 @@ KeymapWindow::KeymapWindow()
.Add(fKeyboardLayoutView)
//.Add(new BStringView("text label", "Sample and Clipboard:"))
.Add(BGroupLayoutBuilder(B_HORIZONTAL, 10)
.Add(fTextControl)
.Add(_CreateDeadKeyMenu(), 0.0)
.AddGlue()
.Add(fSwitchShortcutsButton))
.Add(fTextControl)
.AddGlue(0.0)
.Add(BGroupLayoutBuilder(B_HORIZONTAL, 10)
.AddGlue(0.0)
@@ -153,6 +163,7 @@ KeymapWindow::KeymapWindow()
fAppliedMap = fCurrentMap;
fCurrentMap.SetTarget(this, new BMessage(kMsgKeymapUpdated));
_UpdateDeadKeyMenu();
_UpdateSwitchShortcutButton();
Unlock();
@@ -307,6 +318,71 @@ KeymapWindow::MessageReceived(BMessage* message)
fUserListView->Select(0L);
break;
case kMsgDeadKeyAcuteChanged:
{
BMenuItem *item = fAcuteMenu->FindMarked();
if (item != NULL) {
const char* trigger = item->Label();
if (strcmp(trigger, kDeadKeyTriggerNone) == 0)
trigger = NULL;
fCurrentMap.SetDeadKeyTrigger(kDeadKeyAcute, trigger);
fKeyboardLayoutView->Invalidate();
}
break;
}
case kMsgDeadKeyCircumflexChanged:
{
BMenuItem *item = fCircumflexMenu->FindMarked();
if (item != NULL) {
const char* trigger = item->Label();
if (strcmp(trigger, kDeadKeyTriggerNone) == 0)
trigger = NULL;
fCurrentMap.SetDeadKeyTrigger(kDeadKeyCircumflex, trigger);
fKeyboardLayoutView->Invalidate();
}
break;
}
case kMsgDeadKeyDiaeresisChanged:
{
BMenuItem *item = fDiaeresisMenu->FindMarked();
if (item != NULL) {
const char* trigger = item->Label();
if (strcmp(trigger, kDeadKeyTriggerNone) == 0)
trigger = NULL;
fCurrentMap.SetDeadKeyTrigger(kDeadKeyDiaeresis, trigger);
fKeyboardLayoutView->Invalidate();
}
break;
}
case kMsgDeadKeyGraveChanged:
{
BMenuItem *item = fGraveMenu->FindMarked();
if (item != NULL) {
const char* trigger = item->Label();
if (strcmp(trigger, kDeadKeyTriggerNone) == 0)
trigger = NULL;
fCurrentMap.SetDeadKeyTrigger(kDeadKeyGrave, trigger);
fKeyboardLayoutView->Invalidate();
}
break;
}
case kMsgDeadKeyTildeChanged:
{
BMenuItem *item = fTildeMenu->FindMarked();
if (item != NULL) {
const char* trigger = item->Label();
if (strcmp(trigger, kDeadKeyTriggerNone) == 0)
trigger = NULL;
fCurrentMap.SetDeadKeyTrigger(kDeadKeyTilde, trigger);
fKeyboardLayoutView->Invalidate();
}
break;
}
default:
BWindow::MessageReceived(message);
break;
@@ -372,6 +448,61 @@ KeymapWindow::_CreateMenu()
}
BMenuBar*
KeymapWindow::_CreateDeadKeyMenu()
{
BMenuBar* menuBar = new BMenuBar("deadkeymenubar");
fDeadKeyMenu = new BMenu("Select Dead Keys");
menuBar->AddItem(fDeadKeyMenu);
fAcuteMenu = new BMenu("Acute Trigger");
fAcuteMenu->SetRadioMode(true);
fAcuteMenu->AddItem(new BMenuItem("\xC2\xB4",
new BMessage(kMsgDeadKeyAcuteChanged)));
fAcuteMenu->AddItem(new BMenuItem("'",
new BMessage(kMsgDeadKeyAcuteChanged)));
fAcuteMenu->AddItem(new BMenuItem(kDeadKeyTriggerNone,
new BMessage(kMsgDeadKeyAcuteChanged)));
fDeadKeyMenu->AddItem(fAcuteMenu);
fCircumflexMenu = new BMenu("Circumflex Trigger");
fCircumflexMenu->SetRadioMode(true);
fCircumflexMenu->AddItem(new BMenuItem("^",
new BMessage(kMsgDeadKeyCircumflexChanged)));
fCircumflexMenu->AddItem(new BMenuItem(kDeadKeyTriggerNone,
new BMessage(kMsgDeadKeyCircumflexChanged)));
fDeadKeyMenu->AddItem(fCircumflexMenu);
fDiaeresisMenu = new BMenu("Diaeresis Trigger");
fDiaeresisMenu->SetRadioMode(true);
fDiaeresisMenu->AddItem(new BMenuItem("\xC2\xA8",
new BMessage(kMsgDeadKeyDiaeresisChanged)));
fDiaeresisMenu->AddItem(new BMenuItem("\"",
new BMessage(kMsgDeadKeyDiaeresisChanged)));
fDiaeresisMenu->AddItem(new BMenuItem(kDeadKeyTriggerNone,
new BMessage(kMsgDeadKeyDiaeresisChanged)));
fDeadKeyMenu->AddItem(fDiaeresisMenu);
fGraveMenu = new BMenu("Grave Trigger");
fGraveMenu->SetRadioMode(true);
fGraveMenu->AddItem(new BMenuItem("`",
new BMessage(kMsgDeadKeyGraveChanged)));
fGraveMenu->AddItem(new BMenuItem(kDeadKeyTriggerNone,
new BMessage(kMsgDeadKeyGraveChanged)));
fDeadKeyMenu->AddItem(fGraveMenu);
fTildeMenu = new BMenu("Tilde Trigger");
fTildeMenu->SetRadioMode(true);
fTildeMenu->AddItem(new BMenuItem("~",
new BMessage(kMsgDeadKeyTildeChanged)));
fTildeMenu->AddItem(new BMenuItem(kDeadKeyTriggerNone,
new BMessage(kMsgDeadKeyTildeChanged)));
fDeadKeyMenu->AddItem(fTildeMenu);
return menuBar;
}
BView*
KeymapWindow::_CreateMapLists()
{
@@ -457,12 +588,57 @@ KeymapWindow::_UpdateSwitchShortcutButton()
}
/*! Marks the menu items corresponding to the dead key state of the current
key map.
*/
void
KeymapWindow::_UpdateDeadKeyMenu()
{
BString trigger;
fCurrentMap.GetDeadKeyTrigger(kDeadKeyAcute, trigger);
if (!trigger.Length())
trigger = kDeadKeyTriggerNone;
BMenuItem* menuItem = fAcuteMenu->FindItem(trigger.String());
if (menuItem)
menuItem->SetMarked(true);
fCurrentMap.GetDeadKeyTrigger(kDeadKeyCircumflex, trigger);
if (!trigger.Length())
trigger = kDeadKeyTriggerNone;
menuItem = fCircumflexMenu->FindItem(trigger.String());
if (menuItem)
menuItem->SetMarked(true);
fCurrentMap.GetDeadKeyTrigger(kDeadKeyDiaeresis, trigger);
if (!trigger.Length())
trigger = kDeadKeyTriggerNone;
menuItem = fDiaeresisMenu->FindItem(trigger.String());
if (menuItem)
menuItem->SetMarked(true);
fCurrentMap.GetDeadKeyTrigger(kDeadKeyGrave, trigger);
if (!trigger.Length())
trigger = kDeadKeyTriggerNone;
menuItem = fGraveMenu->FindItem(trigger.String());
if (menuItem)
menuItem->SetMarked(true);
fCurrentMap.GetDeadKeyTrigger(kDeadKeyTilde, trigger);
if (!trigger.Length())
trigger = kDeadKeyTriggerNone;
menuItem = fTildeMenu->FindItem(trigger.String());
if (menuItem)
menuItem->SetMarked(true);
}
void
KeymapWindow::_UpdateButtons()
{
fUseButton->SetEnabled(!fCurrentMap.Equals(fAppliedMap));
fRevertButton->SetEnabled(!fCurrentMap.Equals(fPreviousMap));
_UpdateDeadKeyMenu();
_UpdateSwitchShortcutButton();
}
+9
View File
@@ -46,6 +46,9 @@ protected:
void _UseKeymap();
void _RevertKeymap();
BMenuBar* _CreateDeadKeyMenu();
void _UpdateDeadKeyMenu();
void _FillSystemMaps();
void _FillUserMaps();
void _SetListViewSize(BListView* listView);
@@ -64,6 +67,12 @@ protected:
KeyboardLayoutView* fKeyboardLayoutView;
BTextControl* fTextControl;
BButton* fSwitchShortcutsButton;
BMenu* fDeadKeyMenu;
BMenu* fAcuteMenu;
BMenu* fCircumflexMenu;
BMenu* fDiaeresisMenu;
BMenu* fGraveMenu;
BMenu* fTildeMenu;
Keymap fCurrentMap;
Keymap fPreviousMap;