|
12 | 12 | #include <memory> |
13 | 13 | #include <mutex> |
14 | 14 | #include <optional> |
| 15 | +#include <vector> |
15 | 16 |
|
16 | 17 | // platform includes |
17 | 18 | #include <ApplicationServices/ApplicationServices.h> |
@@ -508,7 +509,47 @@ namespace lvh::detail { |
508 | 509 | return OperationStatus::success(); |
509 | 510 | } |
510 | 511 |
|
511 | | - return OperationStatus::failure(unsupported_profile, "macOS keyboard text input is not implemented"); |
| 512 | + if (!state_->keyboard_source) { |
| 513 | + return OperationStatus::failure(backend_failure, "macOS keyboard event source is unavailable"); |
| 514 | + } |
| 515 | + |
| 516 | + const auto text = CFStringCreateWithBytes( |
| 517 | + kCFAllocatorDefault, |
| 518 | + reinterpret_cast<const UInt8 *>(event.text.data()), |
| 519 | + static_cast<CFIndex>(event.text.size()), |
| 520 | + kCFStringEncodingUTF8, |
| 521 | + false |
| 522 | + ); |
| 523 | + if (!text) { |
| 524 | + return OperationStatus::failure(invalid_argument, "convert UTF-8 text for macOS keyboard input"); |
| 525 | + } |
| 526 | + |
| 527 | + const auto length = CFStringGetLength(text); |
| 528 | + std::vector<UniChar> characters(static_cast<std::size_t>(length)); |
| 529 | + CFStringGetCharacters(text, CFRangeMake(0, length), characters.data()); |
| 530 | + CFRelease(text); |
| 531 | + |
| 532 | + const auto key_down = CGEventCreateKeyboardEvent(state_->keyboard_source, 0, true); |
| 533 | + if (!key_down) { |
| 534 | + return OperationStatus::failure(backend_failure, "create macOS keyboard text key-down event"); |
| 535 | + } |
| 536 | + |
| 537 | + const auto key_up = CGEventCreateKeyboardEvent(state_->keyboard_source, 0, false); |
| 538 | + if (!key_up) { |
| 539 | + CFRelease(key_down); |
| 540 | + return OperationStatus::failure(backend_failure, "create macOS keyboard text key-up event"); |
| 541 | + } |
| 542 | + |
| 543 | + std::lock_guard lock {state_->keyboard_mutex}; |
| 544 | + CGEventKeyboardSetUnicodeString(key_down, characters.size(), characters.data()); |
| 545 | + CGEventKeyboardSetUnicodeString(key_up, characters.size(), characters.data()); |
| 546 | + CGEventSetFlags(key_down, state_->keyboard_flags); |
| 547 | + CGEventSetFlags(key_up, state_->keyboard_flags); |
| 548 | + CGEventPost(kCGSessionEventTap, key_down); |
| 549 | + CGEventPost(kCGSessionEventTap, key_up); |
| 550 | + CFRelease(key_down); |
| 551 | + CFRelease(key_up); |
| 552 | + return OperationStatus::success(); |
512 | 553 | } |
513 | 554 |
|
514 | 555 | OperationStatus close() override { |
|
0 commit comments