| Flutter Windows Embedder |

cursor_handler.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/windows/cursor_handler.h"
6
7 #include <windows.h>
8
9 #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
10 #include "flutter/shell/platform/windows/flutter_windows_engine.h"
11
12 static constexpr char kChannelName[] = "flutter/mousecursor";
13
14 static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor";
15 static constexpr char kKindKey[] = "kind";
16
17 // This method allows creating a custom cursor with rawBGRA buffer, returns a
18 // string to identify the cursor.
19 static constexpr char kCreateCustomCursorMethod[] =
20 "createCustomCursor/windows";
21 // A string, the custom cursor's name.
22 static constexpr char kCustomCursorNameKey[] = "name";
23 // A list of bytes, the custom cursor's rawBGRA buffer.
24 static constexpr char kCustomCursorBufferKey[] = "buffer";
25 // A double, the x coordinate of the custom cursor's hotspot, starting from
26 // left.
27 static constexpr char kCustomCursorHotXKey[] = "hotX";
28 // A double, the y coordinate of the custom cursor's hotspot, starting from top.
29 static constexpr char kCustomCursorHotYKey[] = "hotY";
30 // An int value for the width of the custom cursor.
31 static constexpr char kCustomCursorWidthKey[] = "width";
32 // An int value for the height of the custom cursor.
33 static constexpr char kCustomCursorHeightKey[] = "height";
34
35 // This method also has an argument `kCustomCursorNameKey` for the name
36 // of the cursor to activate.
37 static constexpr char kSetCustomCursorMethod[] = "setCustomCursor/windows";
38
39 // This method also has an argument `kCustomCursorNameKey` for the name
40 // of the cursor to delete.
41 static constexpr char kDeleteCustomCursorMethod[] =
42 "deleteCustomCursor/windows";
43
44 // Error codes used for responses.
45 static constexpr char kCursorError[] = "Cursor error";
46
47 namespace flutter {
48
49 CursorHandler::CursorHandler(BinaryMessenger* messenger,
50 FlutterWindowsEngine* engine)
51 : channel_(std::make_unique<MethodChannel<EncodableValue>>(
52 messenger,
53 kChannelName,
54 &StandardMethodCodec::GetInstance())),
55 engine_(engine) {
56 channel_->SetMethodCallHandler(
57 [this](const MethodCall<EncodableValue>& call,
58 std::unique_ptr<MethodResult<EncodableValue>> result) {
59 HandleMethodCall(call, std::move(result));
60 });
61 }
62
63 void CursorHandler::HandleMethodCall(
64 const MethodCall<EncodableValue>& method_call,
65 std::unique_ptr<MethodResult<EncodableValue>> result) {
66 const std::string& method = method_call.method_name();
67 if (method.compare(kActivateSystemCursorMethod) == 0) {
68 const auto& arguments = std::get<EncodableMap>(*method_call.arguments());
69 auto kind_iter = arguments.find(EncodableValue(std::string(kKindKey)));
70 if (kind_iter == arguments.end()) {
71 result->Error("Argument error",
72 "Missing argument while trying to activate system cursor");
73 return;
74 }
75 const auto& kind = std::get<std::string>(kind_iter->second);
76 engine_->UpdateFlutterCursor(kind);
77 result->Success();
78 } else if (method.compare(kCreateCustomCursorMethod) == 0) {
79 const auto& arguments = std::get<EncodableMap>(*method_call.arguments());
80 auto name_iter =
81 arguments.find(EncodableValue(std::string(kCustomCursorNameKey)));
82 if (name_iter == arguments.end()) {
83 result->Error(
84 "Argument error",
85 "Missing argument name while trying to customize system cursor");
86 return;
87 }
88 auto name = std::get<std::string>(name_iter->second);
89 auto buffer_iter =
90 arguments.find(EncodableValue(std::string(kCustomCursorBufferKey)));
91 if (buffer_iter == arguments.end()) {
92 result->Error(
93 "Argument error",
94 "Missing argument buffer while trying to customize system cursor");
95 return;
96 }
97 auto buffer = std::get<std::vector<uint8_t>>(buffer_iter->second);
98 auto width_iter =
99 arguments.find(EncodableValue(std::string(kCustomCursorWidthKey)));
100 if (width_iter == arguments.end()) {
101 result->Error(
102 "Argument error",
103 "Missing argument width while trying to customize system cursor");
104 return;
105 }
106 auto width = std::get<int>(width_iter->second);
107 auto height_iter =
108 arguments.find(EncodableValue(std::string(kCustomCursorHeightKey)));
109 if (height_iter == arguments.end()) {
110 result->Error(
111 "Argument error",
112 "Missing argument height while trying to customize system cursor");
113 return;
114 }
115 auto height = std::get<int>(height_iter->second);
116 auto hot_x_iter =
117 arguments.find(EncodableValue(std::string(kCustomCursorHotXKey)));
118 if (hot_x_iter == arguments.end()) {
119 result->Error(
120 "Argument error",
121 "Missing argument hotX while trying to customize system cursor");
122 return;
123 }
124 auto hot_x = std::get<double>(hot_x_iter->second);
125 auto hot_y_iter =
126 arguments.find(EncodableValue(std::string(kCustomCursorHotYKey)));
127 if (hot_y_iter == arguments.end()) {
128 result->Error(
129 "Argument error",
130 "Missing argument hotY while trying to customize system cursor");
131 return;
132 }
133 auto hot_y = std::get<double>(hot_y_iter->second);
134 HCURSOR cursor = GetCursorFromBuffer(buffer, hot_x, hot_y, width, height);
135 if (cursor == nullptr) {
136 result->Error("Argument error",
137 "Argument must contains a valid rawBGRA bitmap");
138 return;
139 }
140 // Push the cursor into the cache map.
141 custom_cursors_.emplace(name, std::move(cursor));
142 result->Success(flutter::EncodableValue(std::move(name)));
143 } else if (method.compare(kSetCustomCursorMethod) == 0) {
144 const auto& arguments = std::get<EncodableMap>(*method_call.arguments());
145 auto name_iter =
146 arguments.find(EncodableValue(std::string(kCustomCursorNameKey)));
147 if (name_iter == arguments.end()) {
148 result->Error("Argument error",
149 "Missing argument key while trying to set a custom cursor");
150 return;
151 }
152 auto name = std::get<std::string>(name_iter->second);
153 if (custom_cursors_.find(name) == custom_cursors_.end()) {
154 result->Error(
155 "Argument error",
156 "The custom cursor identified by the argument key cannot be found");
157 return;
158 }
159 HCURSOR cursor = custom_cursors_[name];
160 engine_->SetFlutterCursor(cursor);
161 result->Success();
162 } else if (method.compare(kDeleteCustomCursorMethod) == 0) {
163 const auto& arguments = std::get<EncodableMap>(*method_call.arguments());
164 auto name_iter =
165 arguments.find(EncodableValue(std::string(kCustomCursorNameKey)));
166 if (name_iter == arguments.end()) {
167 result->Error(
168 "Argument error",
169 "Missing argument key while trying to delete a custom cursor");
170 return;
171 }
172 auto name = std::get<std::string>(name_iter->second);
173 auto it = custom_cursors_.find(name);
174 // If the specified cursor name is not found, the deletion is a noop and
175 // returns success.
176 if (it != custom_cursors_.end()) {
177 DeleteObject(it->second);
178 custom_cursors_.erase(it);
179 }
180 result->Success();
181 } else {
182 result->NotImplemented();
183 }
184 }
185
186 HCURSOR GetCursorFromBuffer(const std::vector<uint8_t>& buffer,
187 double hot_x,
188 double hot_y,
189 int width,
190 int height) {
191 HCURSOR cursor = nullptr;
192 HDC display_dc = GetDC(NULL);
193 // Flutter should returns rawBGRA, which has 8bits * 4channels.
194 BITMAPINFO bmi;
195 memset(&bmi, 0, sizeof(bmi));
196 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
197 bmi.bmiHeader.biWidth = width;
198 bmi.bmiHeader.biHeight = -height;
199 bmi.bmiHeader.biPlanes = 1;
200 bmi.bmiHeader.biBitCount = 32;
201 bmi.bmiHeader.biCompression = BI_RGB;
202 bmi.bmiHeader.biSizeImage = width * height * 4;
203 // Create the pixmap DIB section
204 uint8_t* pixels = 0;
205 HBITMAP bitmap =
206 CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (void**)&pixels, 0, 0);
207 ReleaseDC(0, display_dc);
208 if (!bitmap || !pixels) {
209 return nullptr;
210 }
211 int bytes_per_line = width * 4;
212 for (int y = 0; y < height; ++y) {
213 memcpy(pixels + y * bytes_per_line, &buffer[bytes_per_line * y],
214 bytes_per_line);
215 }
216 HBITMAP mask;
217 GetMaskBitmaps(bitmap, mask);
218 ICONINFO icon_info;
219 icon_info.fIcon = 0;
220 icon_info.xHotspot = hot_x;
221 icon_info.yHotspot = hot_y;
222 icon_info.hbmMask = mask;
223 icon_info.hbmColor = bitmap;
224 cursor = CreateIconIndirect(&icon_info);
225 DeleteObject(mask);
226 DeleteObject(bitmap);
227 return cursor;
228 }
229
230 void GetMaskBitmaps(HBITMAP bitmap, HBITMAP& mask_bitmap) {
231 HDC h_dc = ::GetDC(NULL);
232 HDC h_main_dc = ::CreateCompatibleDC(h_dc);
233 HDC h_and_mask_dc = ::CreateCompatibleDC(h_dc);
234
235 // Get the dimensions of the source bitmap
236 BITMAP bm;
237 ::GetObject(bitmap, sizeof(BITMAP), &bm);
238 mask_bitmap = ::CreateCompatibleBitmap(h_dc, bm.bmWidth, bm.bmHeight);
239
240 // Select the bitmaps to DC
241 HBITMAP h_old_main_bitmap = (HBITMAP)::SelectObject(h_main_dc, bitmap);
242 HBITMAP h_old_and_mask_bitmap =
243 (HBITMAP)::SelectObject(h_and_mask_dc, mask_bitmap);
244
245 // Scan each pixel of the souce bitmap and create the masks
246 COLORREF main_bit_pixel;
247 for (int x = 0; x < bm.bmWidth; ++x) {
248 for (int y = 0; y < bm.bmHeight; ++y) {
249 main_bit_pixel = ::GetPixel(h_main_dc, x, y);
250 if (main_bit_pixel == RGB(0, 0, 0)) {
251 ::SetPixel(h_and_mask_dc, x, y, RGB(255, 255, 255));
252 } else {
253 ::SetPixel(h_and_mask_dc, x, y, RGB(0, 0, 0));
254 }
255 }
256 }
257 ::SelectObject(h_main_dc, h_old_main_bitmap);
258 ::SelectObject(h_and_mask_dc, h_old_and_mask_bitmap);
259
260 ::DeleteDC(h_and_mask_dc);
261 ::DeleteDC(h_main_dc);
262
263 ::ReleaseDC(NULL, h_dc);
264 }
265
266 } // namespace flutter
flutter::BinaryMessenger
Definition: binary_messenger.h:28
flutter::CursorHandler::CursorHandler
CursorHandler(flutter::BinaryMessenger *messenger, flutter::FlutterWindowsEngine *engine)
Definition: cursor_handler.cc:49
flutter::EncodableValue
Definition: encodable_value.h:165
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:91
flutter::FlutterWindowsEngine::UpdateFlutterCursor
void UpdateFlutterCursor(const std::string &cursor_name) const
Definition: flutter_windows_engine.cc:1070
flutter::FlutterWindowsEngine::SetFlutterCursor
void SetFlutterCursor(HCURSOR cursor) const
Definition: flutter_windows_engine.cc:1075
flutter::MethodCall
Definition: method_call.h:18
flutter::MethodCall::method_name
const std::string & method_name() const
Definition: method_call.h:31
flutter::MethodCall::arguments
const T * arguments() const
Definition: method_call.h:34
flutter::MethodChannel
Definition: method_channel.h:34
flutter::MethodResult< EncodableValue >
flutter::StandardMethodCodec
Definition: standard_method_codec.h:18
kDeleteCustomCursorMethod
static constexpr char kDeleteCustomCursorMethod[]
Definition: cursor_handler.cc:41
kActivateSystemCursorMethod
static constexpr char kActivateSystemCursorMethod[]
Definition: cursor_handler.cc:14
kCustomCursorHotXKey
static constexpr char kCustomCursorHotXKey[]
Definition: cursor_handler.cc:27
kCustomCursorWidthKey
static constexpr char kCustomCursorWidthKey[]
Definition: cursor_handler.cc:31
kKindKey
static constexpr char kKindKey[]
Definition: cursor_handler.cc:15
kChannelName
static constexpr char kChannelName[]
Definition: cursor_handler.cc:12
kCustomCursorHotYKey
static constexpr char kCustomCursorHotYKey[]
Definition: cursor_handler.cc:29
kCustomCursorNameKey
static constexpr char kCustomCursorNameKey[]
Definition: cursor_handler.cc:22
kCreateCustomCursorMethod
static constexpr char kCreateCustomCursorMethod[]
Definition: cursor_handler.cc:19
kSetCustomCursorMethod
static constexpr char kSetCustomCursorMethod[]
Definition: cursor_handler.cc:37
kCustomCursorBufferKey
static constexpr char kCustomCursorBufferKey[]
Definition: cursor_handler.cc:24
kCursorError
static constexpr char kCursorError[]
Definition: cursor_handler.cc:45
kCustomCursorHeightKey
static constexpr char kCustomCursorHeightKey[]
Definition: cursor_handler.cc:33
cursor_handler.h
flutter_windows_engine.h
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::GetMaskBitmaps
void GetMaskBitmaps(HBITMAP bitmap, HBITMAP &mask_bitmap)
Definition: cursor_handler.cc:230
flutter::GetCursorFromBuffer
HCURSOR GetCursorFromBuffer(const std::vector< uint8_t > &buffer, double hot_x, double hot_y, int width, int height)
Definition: cursor_handler.cc:186
standard_method_codec.h