mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The current text input manager is win32-specific due to its use of IMM32. For UWP, we'll need a TSF implementation. Once that happens we'll want to extract out a TextInputManager interface and add a separate UWP implementation of this class.
141 lines
3.8 KiB
C++
141 lines
3.8 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "flutter/shell/platform/windows/text_input_manager_win32.h"
|
|
|
|
#include <imm.h>
|
|
|
|
#include <memory>
|
|
|
|
namespace flutter {
|
|
|
|
void TextInputManagerWin32::SetWindowHandle(HWND window_handle) {
|
|
window_handle_ = window_handle;
|
|
}
|
|
|
|
void TextInputManagerWin32::CreateImeWindow() {
|
|
if (window_handle_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// Some IMEs ignore calls to ::ImmSetCandidateWindow() and use the position of
|
|
// the current system caret instead via ::GetCaretPos(). In order to behave
|
|
// as expected with these IMEs, we create a temporary system caret.
|
|
if (!ime_active_) {
|
|
::CreateCaret(window_handle_, nullptr, 1, 1);
|
|
}
|
|
ime_active_ = true;
|
|
|
|
// Set the position of the IME windows.
|
|
UpdateImeWindow();
|
|
}
|
|
|
|
void TextInputManagerWin32::DestroyImeWindow() {
|
|
if (window_handle_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// Destroy the system caret created in CreateImeWindow().
|
|
if (ime_active_) {
|
|
::DestroyCaret();
|
|
}
|
|
ime_active_ = false;
|
|
}
|
|
|
|
void TextInputManagerWin32::UpdateImeWindow() {
|
|
if (window_handle_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
HIMC imm_context = ::ImmGetContext(window_handle_);
|
|
if (imm_context) {
|
|
MoveImeWindow(imm_context);
|
|
::ImmReleaseContext(window_handle_, imm_context);
|
|
}
|
|
}
|
|
|
|
void TextInputManagerWin32::UpdateCaretRect(const Rect& rect) {
|
|
caret_rect_ = rect;
|
|
|
|
if (window_handle_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// TODO(cbracken): wrap these in an RAII container.
|
|
HIMC imm_context = ::ImmGetContext(window_handle_);
|
|
if (imm_context) {
|
|
MoveImeWindow(imm_context);
|
|
::ImmReleaseContext(window_handle_, imm_context);
|
|
}
|
|
}
|
|
|
|
long TextInputManagerWin32::GetComposingCursorPosition() const {
|
|
if (window_handle_ == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
HIMC imm_context = ::ImmGetContext(window_handle_);
|
|
if (imm_context) {
|
|
// Read the cursor position within the composing string.
|
|
const int pos =
|
|
ImmGetCompositionStringW(imm_context, GCS_CURSORPOS, nullptr, 0);
|
|
::ImmReleaseContext(window_handle_, imm_context);
|
|
return pos;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
std::optional<std::u16string> TextInputManagerWin32::GetComposingString()
|
|
const {
|
|
return GetString(GCS_COMPSTR);
|
|
}
|
|
|
|
std::optional<std::u16string> TextInputManagerWin32::GetResultString() const {
|
|
return GetString(GCS_RESULTSTR);
|
|
}
|
|
|
|
std::optional<std::u16string> TextInputManagerWin32::GetString(int type) const {
|
|
if (window_handle_ == nullptr || !ime_active_) {
|
|
return std::nullopt;
|
|
}
|
|
HIMC imm_context = ::ImmGetContext(window_handle_);
|
|
if (imm_context) {
|
|
// Read the composing string length.
|
|
const long compose_bytes =
|
|
::ImmGetCompositionString(imm_context, type, nullptr, 0);
|
|
const long compose_length = compose_bytes / sizeof(wchar_t);
|
|
if (compose_length <= 0) {
|
|
::ImmReleaseContext(window_handle_, imm_context);
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::u16string text(compose_length, '\0');
|
|
::ImmGetCompositionString(imm_context, type, &text[0], compose_bytes);
|
|
::ImmReleaseContext(window_handle_, imm_context);
|
|
return text;
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
void TextInputManagerWin32::MoveImeWindow(HIMC imm_context) {
|
|
if (GetFocus() != window_handle_ || !ime_active_) {
|
|
return;
|
|
}
|
|
LONG x = caret_rect_.left();
|
|
LONG y = caret_rect_.top();
|
|
::SetCaretPos(x, y);
|
|
|
|
COMPOSITIONFORM cf = {CFS_POINT, {x, y}};
|
|
::ImmSetCompositionWindow(imm_context, &cf);
|
|
|
|
CANDIDATEFORM candidate_form = {0, CFS_CANDIDATEPOS, {x, y}, {0, 0, 0, 0}};
|
|
::ImmSetCandidateWindow(imm_context, &candidate_form);
|
|
}
|
|
|
|
} // namespace flutter
|