FlutterのWindowsアプリで、TextFieldフォーカス時にIMEをオン/オフ切り替える機能を実装してみました。
最初、TextFieldのTextInputTypeを使ってキーボードをphone
やemailAddress
に指定すればIMEが切り替わるのでは、と思い試しましたが、切り替わりませんでした。
プラグインでIMEを切り替えられるものを探しましたが見つからなかったので、以下を参考にwin32 APIを呼び出す方法で実装しました。
https://docs.flutter.dev/development/platform-integration/platform-channels#step-5-add-a-windows-platform-specific-implementation
上記に書かれてるように、まずwindows/runner/flutter_window.cpp
の#include "flutter_window.h"
の後に以下を追記します。
#include <flutter/event_channel.h>
#include <flutter/event_sink.h>
#include <flutter/event_stream_handler_functions.h>
#include <flutter/method_channel.h>
#include <flutter/standard_method_codec.h>
#include <windows.h>
#include <memory>
dllを呼び出すため以下をflutter_window.cppに記述します。
#pragma comment(lib, "imm32.lib")
#pragma comment(lib, "user32.lib")
FlutterWindow::OnCreate
メソッドを編集し、チャンネル名 hoge.flutter.dev/ime
に結びついた flutter::MethodChannel
を作成します。
bool FlutterWindow::OnCreate() {
// ...
flutter::MethodChannel<> channel(
flutter_controller_->engine()->messenger(), "hoge.flutter.dev/ime",
&flutter::StandardMethodCodec::GetInstance());
channel.SetMethodCallHandler(
[](const flutter::MethodCall<>& call,
std::unique_ptr<flutter::MethodResult<>> result) {
HWND hwnd = GetForegroundWindow();
HIMC himc = ImmGetContext(hwnd);
if (call.method_name() == "imeOn") {
ImmSetOpenStatus(himc, true);
} else {
ImmSetOpenStatus(himc, false);
}
ImmReleaseContext(hwnd, himc);
result->Success();
});
return true;
}
次にFlutter側でチャネルを介してメッセージを送信するようにします。
以下のWidgetを作成します。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class ToggleIme extends StatelessWidget {
final Widget child;
final bool enable;
const ToggleIme({super.key, required this.child, required this.enable });
static const platform = MethodChannel('hoge.flutter.dev/ime');
@override
Widget build(BuildContext context) {
return Focus(
skipTraversal: true,
child: child,
onFocusChange: (hasFocus) {
if (hasFocus) {
if (enable) {
platform.invokeMethod('imeOn');
} else {
platform.invokeMethod('imeOff');
}
}
} ,
);
}
}
TextFieldを以下のような感じでラップします。
ToggleIme(
enable: false,
child: TextField(),
)
これでTextFieldフォーカス時にIMEがオフになるようになりました。
タグ: Flutter