* dead keys can now be enabled/disabled via middle mouse button

* fDragKey must be reset in MouseUp() as otherwise it is not possible to
  drag a key from one keymap to the textview and then from the textview to the
  same key of another keymap
* _HandleDeadKey() now ignores modifier keys as otherwise dead keys that
  required pressing a modifier (like the tilde on the German keyboard) failed 
  to highlight the resulting characters
What's still missing is a way to edit the resulting characters for each dead key, but I am not yet sure how to do that in an elegant way

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30699 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe 2009-05-10 13:47:54 +00:00
parent 6f260d075b
commit 8365643720
4 changed files with 170 additions and 80 deletions

View File

@ -33,6 +33,7 @@ KeyboardLayoutView::KeyboardLayoutView(const char* name)
fEditable(true),
fModifiers(0),
fDeadKey(0),
fButtons(0),
fDragKey(NULL),
fDropTarget(NULL),
fOldSize(0, 0)
@ -139,25 +140,45 @@ KeyboardLayoutView::MouseDown(BPoint point)
if (key == NULL)
return;
if (fKeymap != NULL && fKeymap->IsModifierKey(key->code)) {
if (_KeyState(key->code)) {
uint32 modifier = fKeymap->Modifier(key->code);
if ((modifier & modifiers()) == 0) {
_SetKeyState(key->code, false);
fModifiers &= ~modifier;
int32 buttons = 0;
if (Looper() != NULL && Looper()->CurrentMessage() != NULL)
Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
if ((buttons & B_TERTIARY_MOUSE_BUTTON) != 0
&& (fButtons & B_TERTIARY_MOUSE_BUTTON) == 0) {
// toggle the "deadness" of dead keys via middle mouse button
if (fKeymap != NULL) {
bool isEnabled = false;
uint8 deadKey
= fKeymap->IsDeadKey(key->code, fModifiers, &isEnabled);
if (deadKey > 0) {
fKeymap->SetDeadKeyEnabled(key->code, fModifiers, !isEnabled);
_InvalidateKey(key);
}
}
} else {
if (fKeymap != NULL && fKeymap->IsModifierKey(key->code)) {
if (_KeyState(key->code)) {
uint32 modifier = fKeymap->Modifier(key->code);
if ((modifier & modifiers()) == 0) {
_SetKeyState(key->code, false);
fModifiers &= ~modifier;
Invalidate();
}
} else {
_SetKeyState(key->code, true);
fModifiers |= fKeymap->Modifier(key->code);
Invalidate();
}
// TODO: if possible, we could handle the lock keys for real
} else {
_SetKeyState(key->code, true);
fModifiers |= fKeymap->Modifier(key->code);
Invalidate();
_InvalidateKey(key);
}
// TODO: if possible, we could handle the lock keys for real
} else {
_SetKeyState(key->code, true);
_InvalidateKey(key);
}
fButtons = buttons;
}
@ -165,23 +186,38 @@ void
KeyboardLayoutView::MouseUp(BPoint point)
{
Key* key = _KeyAt(fClickPoint);
int32 buttons = 0;
if (Looper() != NULL && Looper()->CurrentMessage() != NULL)
Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
if (key != NULL) {
// modifier keys are sticky when used with the mouse
if (fKeymap != NULL && fKeymap->IsModifierKey(key->code))
return;
if ((fButtons & B_TERTIARY_MOUSE_BUTTON) != 0
&& (buttons & B_TERTIARY_MOUSE_BUTTON) == 0) {
_SetKeyState(key->code, false);
_InvalidateKey(key);
fButtons = buttons;
} else {
fButtons = buttons;
_SetKeyState(key->code, false);
// modifier keys are sticky when used with the mouse
if (fKeymap != NULL && fKeymap->IsModifierKey(key->code))
return;
if (_HandleDeadKey(key->code, fModifiers) && fDeadKey != 0)
return;
_SetKeyState(key->code, false);
_InvalidateKey(key);
if (_HandleDeadKey(key->code, fModifiers) && fDeadKey != 0)
return;
if (fDragKey == NULL && fKeymap != NULL) {
// Send fake key down message to target
_SendFakeKeyDown(key);
_InvalidateKey(key);
if (fDragKey == NULL && fKeymap != NULL) {
// Send fake key down message to target
_SendFakeKeyDown(key);
}
}
}
fDragKey = NULL;
}
@ -192,6 +228,10 @@ KeyboardLayoutView::MouseMoved(BPoint point, uint32 transit,
if (fKeymap == NULL)
return;
// rule out dragging for tertiary mouse button
if ((fButtons & B_TERTIARY_MOUSE_BUTTON) != 0)
return;
if (dragMessage != NULL) {
if (fEditable) {
_InvalidateKey(fDropTarget);
@ -202,7 +242,7 @@ KeyboardLayoutView::MouseMoved(BPoint point, uint32 transit,
return;
}
int32 buttons;
if (Window()->CurrentMessage() == NULL
|| Window()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK
@ -515,7 +555,7 @@ KeyboardLayoutView::_DrawKeyButton(BView* view, BRect& rect, BRect updateRect,
{
be_control_look->DrawButtonFrame(view, rect, updateRect, base,
background, pressed ? BControlLook::B_ACTIVATED : 0);
be_control_look->DrawButtonBackground(view, rect, updateRect,
be_control_look->DrawButtonBackground(view, rect, updateRect,
base, pressed ? BControlLook::B_ACTIVATED : 0);
}
@ -529,11 +569,12 @@ KeyboardLayoutView::_DrawKey(BView* view, BRect updateRect, const Key* key,
key_kind keyKind = kNormalKey;
int32 deadKey = 0;
bool secondDeadKey = false;
bool isDeadKeyEnabled = true;
char text[32];
if (fKeymap != NULL) {
_GetKeyLabel(key, text, sizeof(text), keyKind);
deadKey = fKeymap->IsDeadKey(key->code, fModifiers);
deadKey = fKeymap->IsDeadKey(key->code, fModifiers, &isDeadKeyEnabled);
secondDeadKey = fKeymap->IsDeadSecondKey(key->code, fModifiers,
fDeadKey);
} else {
@ -545,7 +586,7 @@ KeyboardLayoutView::_DrawKey(BView* view, BRect updateRect, const Key* key,
if (secondDeadKey)
base = kSecondDeadKeyColor;
else if (deadKey > 0)
else if (deadKey > 0 && isDeadKeyEnabled)
base = kDeadKeyColor;
if (key->shape == kRectangleKeyShape) {
@ -641,7 +682,7 @@ KeyboardLayoutView::_DrawIndicator(BView* view, BRect updateRect,
be_control_look->DrawButtonFrame(view, rect, updateRect, base,
background, BControlLook::B_DISABLED);
be_control_look->DrawButtonBackground(view, rect, updateRect,
be_control_look->DrawButtonBackground(view, rect, updateRect,
base, BControlLook::B_DISABLED);
}
@ -857,14 +898,17 @@ KeyboardLayoutView::_InvalidateKey(const Key* key)
bool
KeyboardLayoutView::_HandleDeadKey(uint32 key, int32 modifiers)
{
if (fKeymap == NULL)
if (fKeymap == NULL || fKeymap->IsModifierKey(key))
return false;
int32 deadKey = fKeymap->IsDeadKey(key, modifiers);
bool isEnabled = false;
int32 deadKey = fKeymap->IsDeadKey(key, modifiers, &isEnabled);
if (fDeadKey != deadKey) {
Invalidate();
fDeadKey = deadKey;
return true;
if (isEnabled) {
Invalidate();
fDeadKey = deadKey;
return true;
}
} else if (fDeadKey != 0) {
Invalidate();
fDeadKey = 0;

View File

@ -97,6 +97,7 @@ private:
uint8 fKeyState[16];
int32 fModifiers;
int32 fDeadKey;
int32 fButtons;
BPoint fClickPoint;
Key* fDragKey;

View File

@ -351,57 +351,28 @@ Keymap::SetModifier(uint32 keyCode, uint32 modifier)
}
//! Checks whether a key is a dead key.
/*! Checks whether a key is a dead key.
If it is, the enabled/disabled state of that dead key will be passed
out via isEnabled (isEnabled is not touched for non-dead keys).
*/
uint8
Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers)
Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers, bool* isEnabled)
{
if (fChars == NULL)
return 0;
uint32 tableMask = 0;
int32 offset = _Offset(keyCode, modifiers, &tableMask);
if (offset <= 0)
return 0;
uint32 numBytes = fChars[offset];
if (!numBytes)
return 0;
char chars[4];
strncpy(chars, &fChars[offset + 1], numBytes);
chars[numBytes] = 0;
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]
};
uint32 deadTables[] = {
fKeys.acute_tables,
fKeys.grave_tables,
fKeys.circumflex_tables,
fKeys.dieresis_tables,
fKeys.tilde_tables
};
for (int32 i = 0; i < 5; i++) {
if ((deadTables[i] & tableMask) == 0)
continue;
if (offset == deadOffsets[i])
return i + 1;
uint32 deadNumBytes = fChars[deadOffsets[i]];
if (!deadNumBytes)
continue;
if (strncmp(chars, &fChars[deadOffsets[i] + 1], deadNumBytes) == 0)
return i + 1;
uint8 deadKeyIndex = _GetDeadKeyIndex(offset);
if (deadKeyIndex > 0 && isEnabled != NULL) {
uint32 deadTables[] = {
fKeys.acute_tables,
fKeys.grave_tables,
fKeys.circumflex_tables,
fKeys.dieresis_tables,
fKeys.tilde_tables
};
*isEnabled = (deadTables[deadKeyIndex - 1] & tableMask) != 0;
}
return 0;
return deadKeyIndex;
}
@ -448,6 +419,33 @@ Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey)
}
//! Enables/disables the "deadness" of the given keycode/modifier combo.
void
Keymap::SetDeadKeyEnabled(uint32 keyCode, uint32 modifiers, bool enabled)
{
uint32 tableMask = 0;
int32 offset = _Offset(keyCode, modifiers, &tableMask);
uint8 deadKeyIndex = _GetDeadKeyIndex(offset);
if (deadKeyIndex > 0) {
uint32* deadTables[] = {
&fKeys.acute_tables,
&fKeys.grave_tables,
&fKeys.circumflex_tables,
&fKeys.dieresis_tables,
&fKeys.tilde_tables
};
if (enabled)
(*deadTables[deadKeyIndex - 1]) |= tableMask;
else
(*deadTables[deadKeyIndex - 1]) &= ~tableMask;
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,
@ -693,3 +691,46 @@ Keymap::_Offset(uint32 keyCode, uint32 modifiers, uint32* _table)
return offset;
}
uint8
Keymap::_GetDeadKeyIndex(int32 offset)
{
if (fChars == NULL || offset <= 0)
return 0;
uint32 numBytes = fChars[offset];
if (!numBytes)
return 0;
char chars[4];
strncpy(chars, &fChars[offset + 1], numBytes);
chars[numBytes] = 0;
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]
};
uint8 result = 0;
for (int32 i = 0; i < 5; i++) {
if (offset == deadOffsets[i]) {
result = i + 1;
break;
}
uint32 deadNumBytes = fChars[deadOffsets[i]];
if (!deadNumBytes)
continue;
if (strncmp(chars, &fChars[deadOffsets[i] + 1], deadNumBytes) == 0) {
result = i + 1;
break;
}
}
return result;
}

View File

@ -33,9 +33,12 @@ public:
uint32 KeyForModifier(uint32 modifier);
status_t SetModifier(uint32 keyCode, uint32 modifier);
uint8 IsDeadKey(uint32 keyCode, uint32 modifiers);
uint8 IsDeadKey(uint32 keyCode, uint32 modifiers,
bool* isEnabled = NULL);
bool IsDeadSecondKey(uint32 keyCode, uint32 modifiers,
uint8 activeDeadKey);
void SetDeadKeyEnabled(uint32 keyCode, uint32 modifiers,
bool enabled);
void GetChars(uint32 keyCode, uint32 modifiers,
uint8 activeDeadKey, char** chars,
int32* numBytes);
@ -54,6 +57,7 @@ public:
private:
int32 _Offset(uint32 keyCode, uint32 modifiers,
uint32* _table = NULL);
uint8 _GetDeadKeyIndex(int32 offset);
char* fChars;
key_map fKeys;