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); } }