void KeyboardLayoutView::MouseDown(BPoint point) { fClickPoint = point; fDragKey = NULL; fDropPoint.x = -1; Key* key = _KeyAt(point); if (key == NULL) return; 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->DeadKey(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); _InvalidateKey(key); } } fButtons = buttons; }
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) { if ((fButtons & B_TERTIARY_MOUSE_BUTTON) != 0 && (buttons & B_TERTIARY_MOUSE_BUTTON) == 0) { _SetKeyState(key->code, false); _InvalidateKey(key); fButtons = buttons; } else { fButtons = buttons; // modifier keys are sticky when used with the mouse if (fKeymap != NULL && fKeymap->IsModifierKey(key->code)) return; _SetKeyState(key->code, false); if (_HandleDeadKey(key->code, fModifiers) && fDeadKey != 0) return; _InvalidateKey(key); if (fDragKey == NULL && fKeymap != NULL) { // Send fake key down message to target _SendFakeKeyDown(key); } } } fDragKey = NULL; }
void KeyboardLayoutView::_KeyChanged(const BMessage* message) { const uint8* state; ssize_t size; int32 key; if (message->FindData("states", B_UINT8_TYPE, (const void**)&state, &size) != B_OK || message->FindInt32("key", &key) != B_OK) return; // Update key state, and invalidate change keys bool checkSingle = true; if (message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN) { if (_HandleDeadKey(key, fModifiers)) checkSingle = false; if (_KeyForCode(key) == NULL) printf("no key for code %" B_PRId32 "\n", key); } for (int32 i = 0; i < 16; i++) { if (fKeyState[i] != state[i]) { uint8 diff = fKeyState[i] ^ state[i]; fKeyState[i] = state[i]; if (!checkSingle || !Window()->IsActive()) continue; for (int32 j = 7; diff != 0; j--, diff >>= 1) { if (diff & 1) { _InvalidateKey(i * 8 + j); } } } }
void KeyboardLayoutView::_InvalidateKey(uint32 code) { _InvalidateKey(_KeyForCode(code)); }
void KeyboardLayoutView::MessageReceived(BMessage* message) { if (message->WasDropped() && fEditable && fDropTarget != NULL && fKeymap != NULL) { int32 keyCode; const char* data; ssize_t size; if (message->FindData("text/plain", B_MIME_DATA, (const void**)&data, &size) == B_OK) { // Automatically convert UTF-8 escaped strings (for example from // CharacterMap) int32 dataSize = 0; uint8 buffer[16]; if (size > 3 && data[0] == '\\' && data[1] == 'x') { char tempBuffer[16]; if (size > 15) size = 15; memcpy(tempBuffer, data, size); tempBuffer[size] = '\0'; data = tempBuffer; while (size > 3 && data[0] == '\\' && data[1] == 'x') { buffer[dataSize++] = strtoul(&data[2], NULL, 16); if ((buffer[dataSize - 1] & 0x80) == 0) break; size -= 4; data += 4; } data = (const char*)buffer; } else if ((data[0] & 0xc0) != 0x80 && (data[0] & 0x80) != 0) { // only accept the first character UTF-8 character while (dataSize < size && (data[dataSize] & 0x80) != 0) { dataSize++; } } else if ((data[0] & 0x80) == 0) { // an ASCII character dataSize = 1; } else { // no valid character beep(); return; } int32 buttons; if (!message->IsSourceRemote() && message->FindInt32("buttons", &buttons) == B_OK && (buttons & B_SECONDARY_MOUSE_BUTTON) != 0 && message->FindInt32("key", &keyCode) == B_OK) { // switch keys if the dropped object came from us Key* key = _KeyForCode(keyCode); if (key == NULL || (key == fDropTarget && fDragModifiers == fModifiers)) return; char* string; int32 numBytes; fKeymap->GetChars(fDropTarget->code, fModifiers, fDeadKey, &string, &numBytes); if (string != NULL) { // switch keys fKeymap->SetKey(fDropTarget->code, fModifiers, fDeadKey, (const char*)data, dataSize); fKeymap->SetKey(key->code, fDragModifiers, fDeadKey, string, numBytes); delete[] string; } else if (fKeymap->IsModifierKey(fDropTarget->code)) { // switch key with modifier fKeymap->SetModifier(key->code, fKeymap->Modifier(fDropTarget->code)); fKeymap->SetKey(fDropTarget->code, fModifiers, fDeadKey, (const char*)data, dataSize); } } else { // Send the old key to the target, so it's not lost entirely _SendKeyDown(fDropTarget); fKeymap->SetKey(fDropTarget->code, fModifiers, fDeadKey, (const char*)data, dataSize); } } else if (!message->IsSourceRemote() && message->FindInt32("key", &keyCode) == B_OK) { // Switch an unmapped key Key* key = _KeyForCode(keyCode); if (key != NULL && key == fDropTarget) return; uint32 modifier = fKeymap->Modifier(keyCode); char* string; int32 numBytes; fKeymap->GetChars(fDropTarget->code, fModifiers, fDeadKey, &string, &numBytes); if (string != NULL) { // switch key with modifier fKeymap->SetModifier(fDropTarget->code, modifier); fKeymap->SetKey(keyCode, fDragModifiers, fDeadKey, string, numBytes); delete[] string; } else { // switch modifier keys fKeymap->SetModifier(keyCode, fKeymap->Modifier(fDropTarget->code)); fKeymap->SetModifier(fDropTarget->code, modifier); } _InvalidateKey(fDragKey); } _InvalidateKey(fDropTarget); fDropTarget = NULL; fDropPoint.x = -1; return; } switch (message->what) { case B_UNMAPPED_KEY_DOWN: case B_UNMAPPED_KEY_UP: _KeyChanged(message); break; case B_MODIFIERS_CHANGED: { int32 newModifiers; if (message->FindInt32("modifiers", &newModifiers) == B_OK && fModifiers != newModifiers) { fModifiers = newModifiers; _EvaluateDropTarget(fDropPoint); if (Window()->IsActive()) Invalidate(); } break; } default: BView::MessageReceived(message); break; } }
void KeyboardLayoutView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage) { if (fKeymap == NULL) return; // prevent dragging for tertiary mouse button if ((fButtons & B_TERTIARY_MOUSE_BUTTON) != 0) return; if (dragMessage != NULL) { if (fEditable) { _InvalidateKey(fDropTarget); fDropPoint = point; _EvaluateDropTarget(point); } return; } int32 buttons; if (Window()->CurrentMessage() == NULL || Window()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK || buttons == 0) return; if (fDragKey == NULL && (fabs(point.x - fClickPoint.x) > 4 || fabs(point.y - fClickPoint.y) > 4)) { // start dragging Key* key = _KeyAt(fClickPoint); if (key == NULL) return; BRect frame = _FrameFor(key); BPoint offset = fClickPoint - frame.LeftTop(); frame.OffsetTo(B_ORIGIN); BRect rect = frame; rect.right--; rect.bottom--; BBitmap* bitmap = new BBitmap(rect, B_RGBA32, true); bitmap->Lock(); BView* view = new BView(rect, "drag", B_FOLLOW_NONE, 0); bitmap->AddChild(view); view->SetHighColor(0, 0, 0, 0); view->FillRect(view->Bounds()); view->SetDrawingMode(B_OP_ALPHA); view->SetHighColor(0, 0, 0, 128); // set the level of transparency by value view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE); _DrawKey(view, frame, key, frame, false); view->Sync(); bitmap->Unlock(); BMessage drag(B_MIME_DATA); drag.AddInt32("key", key->code); char* string; int32 numBytes; fKeymap->GetChars(key->code, fModifiers, fDeadKey, &string, &numBytes); if (string != NULL) { drag.AddData("text/plain", B_MIME_DATA, string, numBytes); delete[] string; } DragMessage(&drag, bitmap, B_OP_ALPHA, offset); fDragKey = key; fDragModifiers = fModifiers; fKeyState[key->code / 8] &= ~(1 << (7 - (key->code & 7))); _InvalidateKey(key); } }