aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuqian Yang <crupest@crupest.life>2025-10-16 21:16:43 +0800
committerYuqian Yang <crupest@crupest.life>2025-10-16 21:16:43 +0800
commita8b83f7b483a516fb92e2e22b3f364d51b7eb273 (patch)
treecc869eaa751935e13b983c0bdd961e9c0be8f44f
parent073a1e3e5af78fb0d220169009fd6a0939b432d2 (diff)
downloadcru-a8b83f7b483a516fb92e2e22b3f364d51b7eb273.tar.gz
cru-a8b83f7b483a516fb92e2e22b3f364d51b7eb273.tar.bz2
cru-a8b83f7b483a516fb92e2e22b3f364d51b7eb273.zip
Resort input method demo.
-rw-r--r--demos/InputMethod/main.cpp207
-rw-r--r--include/cru/base/Range.h4
-rw-r--r--src/base/log/Logger.cpp1
-rw-r--r--src/platform/gui/xcb/InputMethod.cpp6
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);
}