diff options
author | Yuqian Yang <crupest@crupest.life> | 2025-10-16 21:16:43 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-10-16 21:16:43 +0800 |
commit | a8b83f7b483a516fb92e2e22b3f364d51b7eb273 (patch) | |
tree | cc869eaa751935e13b983c0bdd961e9c0be8f44f | |
parent | 073a1e3e5af78fb0d220169009fd6a0939b432d2 (diff) | |
download | cru-a8b83f7b483a516fb92e2e22b3f364d51b7eb273.tar.gz cru-a8b83f7b483a516fb92e2e22b3f364d51b7eb273.tar.bz2 cru-a8b83f7b483a516fb92e2e22b3f364d51b7eb273.zip |
Resort input method demo.
-rw-r--r-- | demos/InputMethod/main.cpp | 207 | ||||
-rw-r--r-- | include/cru/base/Range.h | 4 | ||||
-rw-r--r-- | src/base/log/Logger.cpp | 1 | ||||
-rw-r--r-- | src/platform/gui/xcb/InputMethod.cpp | 6 |
4 files changed, 126 insertions, 92 deletions
diff --git a/demos/InputMethod/main.cpp b/demos/InputMethod/main.cpp index ce7f0c21..4ea5ab72 100644 --- a/demos/InputMethod/main.cpp +++ b/demos/InputMethod/main.cpp @@ -2,9 +2,11 @@ #include "cru/platform/GraphicsBase.h" #include "cru/platform/Matrix.h" #include "cru/platform/bootstrap/Bootstrap.h" +#include "cru/platform/graphics/Brush.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/graphics/Font.h" #include "cru/platform/graphics/Painter.h" +#include "cru/platform/graphics/TextLayout.h" #include "cru/platform/gui/InputMethod.h" #include "cru/platform/gui/UiApplication.h" #include "cru/platform/gui/Window.h" @@ -14,131 +16,162 @@ using namespace cru::platform; using namespace cru::platform::graphics; using namespace cru::platform::gui; -int main() { - IUiApplication* application = bootstrap::CreateUiApplication(); - application->SetQuitOnAllWindowClosed(true); - +struct DemoBrushes { + std::unique_ptr<ISolidColorBrush> black; + std::unique_ptr<ISolidColorBrush> odd_clause; + std::unique_ptr<ISolidColorBrush> even_clause; + std::unique_ptr<ISolidColorBrush> target_clause; +}; + +class DemoWindow { + public: + DemoWindow(IUiApplication* application, DemoBrushes* brushes, + std::shared_ptr<IFont> font); + + private: + DemoBrushes* brushes_; + std::unique_ptr<INativeWindow> window_; + std::unique_ptr<ITextLayout> prompt_text_layout_; + std::unique_ptr<ITextLayout> committed_text_layout_; + String committed_text_; + CompositionText composition_text_; +}; + +DemoWindow::DemoWindow(IUiApplication* application, DemoBrushes* brushes, + std::shared_ptr<IFont> font) + : brushes_(brushes) { auto graphics_factory = application->GetGraphicsFactory(); + window_ = std::unique_ptr<INativeWindow>(application->CreateWindow()); - auto window = application->CreateWindow(); - - auto input_method_context = window->GetInputMethodContext(); - - auto brush = graphics_factory->CreateSolidColorBrush(); - brush->SetColor(colors::black); - - auto odd_clause_brush = graphics_factory->CreateSolidColorBrush(); - odd_clause_brush->SetColor(colors::yellow); - auto even_clause_brush = graphics_factory->CreateSolidColorBrush(); - even_clause_brush->SetColor(colors::green); - auto target_clause_brush = graphics_factory->CreateSolidColorBrush(); - target_clause_brush->SetColor(colors::blue); - - std::shared_ptr<IFont> font = graphics_factory->CreateFont(String{}, 30); + auto input_method_context = window_->GetInputMethodContext(); - auto prompt_text_layout = + prompt_text_layout_ = graphics_factory->CreateTextLayout(font, u"Ctrl+1: Enable IME\n" u"Ctrl+2: Disable IME\n" u"Ctrl+3: Complete composition.\n" u"Ctrl+4: Cancel composition."); - String committed_text; - auto text_layout = graphics_factory->CreateTextLayout(font, u""); - CompositionText composition_text; - - auto update_text_layout_width = [&prompt_text_layout, - &text_layout](const Size& size) { - prompt_text_layout->SetMaxWidth(size.width); - text_layout->SetMaxWidth(size.width); + committed_text_layout_ = graphics_factory->CreateTextLayout(font, u""); + + auto update_text_layout_width = [this](const Size& size) { + prompt_text_layout_->SetMaxWidth(size.width); + committed_text_layout_->SetMaxWidth(size.width); }; - update_text_layout_width(window->GetClientSize()); - window->ResizeEvent()->AddHandler(update_text_layout_width); + update_text_layout_width(window_->GetClientSize()); + window_->ResizeEvent()->AddHandler(update_text_layout_width); - window->PaintEvent()->AddSpyOnlyHandler([&]() { - auto painter = window->BeginPaint(); + window_->PaintEvent()->AddSpyOnlyHandler([this]() { + auto painter = window_->BeginPaint(); painter->Clear(colors::white); - painter->DrawText(Point{}, prompt_text_layout.get(), brush.get()); + painter->DrawText(Point{}, prompt_text_layout_.get(), + brushes_->black.get()); painter->PushState(); painter->ConcatTransform( - Matrix::Translation(0, prompt_text_layout->GetTextBounds().height)); + Matrix::Translation(0, prompt_text_layout_->GetTextBounds().height)); - for (int i = 0; i < static_cast<int>(composition_text.clauses.size()); + for (int i = 0; i < static_cast<int>(composition_text_.clauses.size()); i++) { - const auto& clause = composition_text.clauses[i]; - auto rects = text_layout->TextRangeRect(TextRange::FromTwoSides( - clause.start, clause.end, committed_text.size())); - const auto& b = clause.target - ? target_clause_brush - : (i % 2 ? odd_clause_brush : even_clause_brush); + const auto& clause = composition_text_.clauses[i]; + auto rects = committed_text_layout_->TextRangeRect( + TextRange::FromTwoSides(clause.start - committed_text_.size(), + clause.end - committed_text_.size())); + const auto& b = clause.target ? brushes_->target_clause + : (i % 2 ? brushes_->odd_clause + : brushes_->even_clause); for (auto& rect : rects) { painter->FillRectangle(rect, b.get()); } } - painter->DrawText(Point{}, text_layout.get(), brush.get()); + painter->DrawText(Point{}, committed_text_layout_.get(), + brushes_->black.get()); - const auto cursor_pos = composition_text.selection.position + - static_cast<int>(committed_text.size()); - auto cursor_rect = text_layout->TextSinglePoint(cursor_pos, false); + const auto cursor_pos = composition_text_.selection.position + + static_cast<int>(committed_text_.size()); + auto cursor_rect = + committed_text_layout_->TextSinglePoint(cursor_pos, false); painter->FillRectangle( Rect{cursor_rect.left, cursor_rect.top, 3, cursor_rect.height}, - brush.get()); + brushes_->black.get()); painter->PopState(); painter->EndDraw(); }); - window->KeyDownEvent()->AddHandler( - [&input_method_context](const NativeKeyEventArgs& args) { - if (args.modifier & KeyModifiers::ctrl) { - switch (args.key) { - case KeyCode::N1: - input_method_context->EnableIME(); - break; - case KeyCode::N2: - input_method_context->DisableIME(); - break; - case KeyCode::N3: - input_method_context->CompleteComposition(); - break; - case KeyCode::N4: - input_method_context->CancelComposition(); - break; - default: - break; - } - } - }); + window_->KeyDownEvent()->AddHandler([this](const NativeKeyEventArgs& args) { + auto input_method_context = window_->GetInputMethodContext(); + if (args.modifier & KeyModifiers::ctrl) { + switch (args.key) { + case KeyCode::N1: + input_method_context->EnableIME(); + break; + case KeyCode::N2: + input_method_context->DisableIME(); + break; + case KeyCode::N3: + input_method_context->CompleteComposition(); + break; + case KeyCode::N4: + input_method_context->CancelComposition(); + break; + default: + break; + } + } + }); - auto update_state = [&] { - text_layout->SetText(committed_text + composition_text.text); - auto y = prompt_text_layout->GetTextBounds().height; - const auto cursor_pos = composition_text.selection.position + - static_cast<int>(committed_text.size()); - auto cursor_rect = text_layout->TextSinglePoint(cursor_pos, false); + auto update_state = [this] { + auto input_method_context = window_->GetInputMethodContext(); + committed_text_layout_->SetText(committed_text_ + composition_text_.text); + auto y = prompt_text_layout_->GetTextBounds().height; + const auto cursor_pos = composition_text_.selection.position + + static_cast<int>(committed_text_.size()); + auto cursor_rect = + committed_text_layout_->TextSinglePoint(cursor_pos, false); input_method_context->SetCandidateWindowPosition( {cursor_rect.left, y + cursor_rect.GetBottom()}); - window->RequestRepaint(); + window_->RequestRepaint(); }; - input_method_context->TextEvent()->AddHandler([&](const StringView& c) { - committed_text += c; - update_state(); - }); + input_method_context->TextEvent()->AddHandler( + [this, update_state](const StringView& c) { + committed_text_ += c; + update_state(); + }); - input_method_context->CompositionEvent()->AddHandler([&](auto) { - composition_text = input_method_context->GetCompositionText(); - update_state(); - }); + input_method_context->CompositionEvent()->AddHandler( + [this, update_state](std::nullptr_t) { + auto input_method_context = window_->GetInputMethodContext(); + composition_text_ = input_method_context->GetCompositionText(); + update_state(); + }); - input_method_context->CompositionEndEvent()->AddHandler([&](auto) { - composition_text = {}; - update_state(); - }); + input_method_context->CompositionEndEvent()->AddHandler( + [this, update_state](std::nullptr_t) { + composition_text_ = {}; + update_state(); + }); + + window_->SetVisibility(WindowVisibilityType::Show); +} + +int main() { + IUiApplication* application = bootstrap::CreateUiApplication(); + application->SetQuitOnAllWindowClosed(true); + + auto graphics_factory = application->GetGraphicsFactory(); + + DemoBrushes brushes{graphics_factory->CreateSolidColorBrush(colors::black), + graphics_factory->CreateSolidColorBrush(colors::yellow), + graphics_factory->CreateSolidColorBrush(colors::green), + graphics_factory->CreateSolidColorBrush(colors::blue)}; + + std::shared_ptr<IFont> font = graphics_factory->CreateFont(String{}, 30); - window->SetVisibility(WindowVisibilityType::Show); + DemoWindow window1(application, &brushes, font); + DemoWindow window2(application, &brushes, font); return application->Run(); } diff --git a/include/cru/base/Range.h b/include/cru/base/Range.h index edc2ec55..44c5aca0 100644 --- a/include/cru/base/Range.h +++ b/include/cru/base/Range.h @@ -7,10 +7,6 @@ struct Range final { return Range(start, end - start); } - constexpr static Range FromTwoSides(Index start, Index end, Index offset) { - return Range(start + offset, end - start); - } - constexpr Range() = default; constexpr Range(const Index position, const Index count = 0) : position(position), count(count) {} diff --git a/src/base/log/Logger.cpp b/src/base/log/Logger.cpp index e8714f26..50a41e0f 100644 --- a/src/base/log/Logger.cpp +++ b/src/base/log/Logger.cpp @@ -120,6 +120,7 @@ void Logger::LogThreadRun() { log_queue_condition_variable_.wait( lock, [this] { return !log_queue_.empty() || log_stop_; }); queue = std::move(log_queue_); + log_queue_ = {}; stop = log_stop_; } diff --git a/src/platform/gui/xcb/InputMethod.cpp b/src/platform/gui/xcb/InputMethod.cpp index 2b495925..1d0cd538 100644 --- a/src/platform/gui/xcb/InputMethod.cpp +++ b/src/platform/gui/xcb/InputMethod.cpp @@ -2,6 +2,7 @@ #include "cru/base/log/Logger.h" #include "cru/platform/Check.h" #include "cru/platform/gui/InputMethod.h" +#include "cru/platform/gui/Keyboard.h" #include "cru/platform/gui/xcb/Keyboard.h" #include "cru/platform/gui/xcb/UiApplication.h" #include "cru/platform/gui/xcb/Window.h" @@ -29,7 +30,10 @@ XcbXimInputMethodManager::XcbXimInputMethodManager( auto text = manager->application_->GetXcbKeyboardManager()->KeycodeToUtf8( event->detail); - if (text.empty() || text == "\b") { + auto modifiers = ConvertModifiersOfEvent(event->detail); + if (text.empty() || text == "\b" || + modifiers.Has(KeyModifiers::Alt) || + modifiers.Has(KeyModifiers::Ctrl)) { if (manager->forward_event_callback_) { manager->forward_event_callback_(event); } |