Bumping manifests a=b2g-bump
[gecko.git] / widget / windows / nsIMM32Handler.h
blob656a1bdde4a23e67fa596bf9a2156b89890f9e5c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsIMM32Handler_h__
7 #define nsIMM32Handler_h__
9 #include "nscore.h"
10 #include <windows.h>
11 #include "nsCOMPtr.h"
12 #include "nsString.h"
13 #include "nsTArray.h"
14 #include "nsIWidget.h"
15 #include "mozilla/EventForwards.h"
17 class nsWindow;
18 struct nsIntRect;
20 namespace mozilla {
21 namespace widget {
23 struct MSGResult;
25 } // namespace widget
26 } // namespace mozilla
28 class nsIMEContext
30 public:
31 nsIMEContext(HWND aWnd) : mWnd(aWnd)
33 mIMC = ::ImmGetContext(mWnd);
36 ~nsIMEContext()
38 if (mIMC) {
39 ::ImmReleaseContext(mWnd, mIMC);
40 mIMC = nullptr;
44 HIMC get() const
46 return mIMC;
49 bool IsValid() const
51 return !!mIMC;
54 void SetOpenState(bool aOpen) const
56 if (!mIMC) {
57 return;
59 ::ImmSetOpenStatus(mIMC, aOpen);
62 bool GetOpenState() const
64 if (!mIMC) {
65 return false;
67 return (::ImmGetOpenStatus(mIMC) != FALSE);
70 bool AssociateDefaultContext()
72 // We assume that there is only default IMC, no new IMC has been created.
73 if (mIMC) {
74 return false;
76 if (!::ImmAssociateContextEx(mWnd, nullptr, IACE_DEFAULT)) {
77 return false;
79 mIMC = ::ImmGetContext(mWnd);
80 return (mIMC != nullptr);
83 bool Disassociate()
85 if (!mIMC) {
86 return false;
88 if (!::ImmAssociateContextEx(mWnd, nullptr, 0)) {
89 return false;
91 ::ImmReleaseContext(mWnd, mIMC);
92 mIMC = nullptr;
93 return true;
96 protected:
97 nsIMEContext()
99 NS_ERROR("Don't create nsIMEContext without window handle");
102 nsIMEContext(const nsIMEContext &aSrc) : mWnd(nullptr), mIMC(nullptr)
104 NS_ERROR("Don't copy nsIMEContext");
107 HWND mWnd;
108 HIMC mIMC;
111 class nsIMM32Handler
113 typedef mozilla::widget::MSGResult MSGResult;
114 public:
115 static void Initialize();
116 static void Terminate();
118 // If Process*() returns true, the caller shouldn't do anything anymore.
119 static bool ProcessMessage(nsWindow* aWindow, UINT msg,
120 WPARAM& wParam, LPARAM& lParam,
121 MSGResult& aResult);
122 static bool IsComposing()
124 return IsComposingOnOurEditor() || IsComposingOnPlugin();
126 static bool IsComposingOn(nsWindow* aWindow)
128 return IsComposing() && IsComposingWindow(aWindow);
131 #ifdef DEBUG
133 * IsIMEAvailable() returns TRUE when current keyboard layout has IME.
134 * Otherwise, FALSE.
136 static bool IsIMEAvailable() { return !!::ImmIsIME(::GetKeyboardLayout(0)); }
137 #endif
139 // If aForce is TRUE, these methods doesn't check whether we have composition
140 // or not. If you don't set it to TRUE, these method doesn't commit/cancel
141 // the composition on uexpected window.
142 static void CommitComposition(nsWindow* aWindow, bool aForce = false);
143 static void CancelComposition(nsWindow* aWindow, bool aForce = false);
144 static void OnUpdateComposition(nsWindow* aWindow);
146 static nsIMEUpdatePreference GetIMEUpdatePreference();
148 protected:
149 static void EnsureHandlerInstance();
151 static bool IsComposingOnOurEditor();
152 static bool IsComposingOnPlugin();
153 static bool IsComposingWindow(nsWindow* aWindow);
155 static bool ShouldDrawCompositionStringOurselves();
156 static void InitKeyboardLayout(HKL aKeyboardLayout);
157 static UINT GetKeyboardCodePage();
160 * Checks whether the window is top level window of the composing window.
161 * In this method, the top level window means in all windows, not only in all
162 * OUR windows. I.e., if the aWindow is embedded, this always returns FALSE.
164 static bool IsTopLevelWindowOfComposition(nsWindow* aWindow);
166 static bool ProcessInputLangChangeMessage(nsWindow* aWindow,
167 WPARAM wParam,
168 LPARAM lParam,
169 MSGResult& aResult);
170 static bool ProcessMessageForPlugin(nsWindow* aWindow, UINT msg,
171 WPARAM &wParam, LPARAM &lParam,
172 MSGResult& aResult);
174 nsIMM32Handler();
175 ~nsIMM32Handler();
177 // On*() methods return true if the caller of message handler shouldn't do
178 // anything anymore. Otherwise, false.
179 bool OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction,
180 MSGResult& aResult);
181 static bool OnKeyDownEvent(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
182 MSGResult& aResult);
184 bool OnIMEStartComposition(nsWindow* aWindow, MSGResult& aResult);
185 bool OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
186 WPARAM wParam, LPARAM lParam,
187 MSGResult& aResult);
188 bool OnIMEComposition(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
189 MSGResult& aResult);
190 bool OnIMECompositionOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
191 MSGResult& aResult);
192 bool OnIMEEndComposition(nsWindow* aWindow, MSGResult& aResult);
193 bool OnIMEEndCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
194 LPARAM lParam, MSGResult& aResult);
195 bool OnIMERequest(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
196 MSGResult& aResult);
197 bool OnIMECharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
198 MSGResult& aResult);
199 bool OnChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
200 MSGResult& aResult);
201 bool OnCharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
202 MSGResult& aResult);
203 void OnInputLangChange(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
204 MSGResult& aResult);
206 // These message handlers don't use instance members, we should not create
207 // the instance by the messages. So, they should be static.
208 static bool OnIMEChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
209 MSGResult& aResult);
210 static bool OnIMESetContext(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
211 MSGResult& aResult);
212 static bool OnIMESetContextOnPlugin(nsWindow* aWindow,
213 WPARAM wParam, LPARAM lParam,
214 MSGResult& aResult);
215 static bool OnIMECompositionFull(nsWindow* aWindow, MSGResult& aResult);
216 static bool OnIMENotify(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
217 MSGResult& aResult);
218 static bool OnIMESelect(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
219 MSGResult& aResult);
221 // The result of Handle* method mean "Processed" when it's TRUE.
222 void HandleStartComposition(nsWindow* aWindow,
223 const nsIMEContext &aIMEContext);
224 bool HandleComposition(nsWindow* aWindow, const nsIMEContext &aIMEContext,
225 LPARAM lParam);
226 void HandleEndComposition(nsWindow* aWindow);
227 bool HandleReconvert(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
228 bool HandleQueryCharPosition(nsWindow* aWindow, LPARAM lParam,
229 LRESULT *oResult);
230 bool HandleDocumentFeed(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
233 * When a window's IME context is activating but we have composition on
234 * another window, we should commit our composition because IME context is
235 * shared by all our windows (including plug-ins).
236 * @param aWindow is a new activated window.
237 * If aWindow is our composing window, this method does nothing.
238 * Otherwise, this commits the composition on the previous window.
239 * If this method did commit a composition, this returns TRUE.
241 bool CommitCompositionOnPreviousWindow(nsWindow* aWindow);
244 * ResolveIMECaretPos
245 * Convert the caret rect of a composition event to another widget's
246 * coordinate system.
248 * @param aReferenceWidget The origin widget of aCursorRect.
249 * Typically, this is mReferenceWidget of the
250 * composing events. If the aCursorRect is in screen
251 * coordinates, set nullptr.
252 * @param aCursorRect The cursor rect.
253 * @param aNewOriginWidget aOutRect will be in this widget's coordinates. If
254 * this is nullptr, aOutRect will be in screen
255 * coordinates.
256 * @param aOutRect The converted cursor rect.
258 void ResolveIMECaretPos(nsIWidget* aReferenceWidget,
259 nsIntRect& aCursorRect,
260 nsIWidget* aNewOriginWidget,
261 nsIntRect& aOutRect);
263 bool ConvertToANSIString(const nsAFlatString& aStr,
264 UINT aCodePage,
265 nsACString& aANSIStr);
267 bool SetIMERelatedWindowsPos(nsWindow* aWindow,
268 const nsIMEContext& aIMEContext);
269 void SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
270 const nsIMEContext& aIMEContext);
271 bool GetCharacterRectOfSelectedTextAt(nsWindow* aWindow,
272 uint32_t aOffset,
273 nsIntRect &aCharRect);
274 bool GetCaretRect(nsWindow* aWindow, nsIntRect &aCaretRect);
275 void GetCompositionString(const nsIMEContext &aIMEContext, DWORD aIndex);
277 * Get the current target clause of composition string.
278 * If there are one or more characters whose attribute is ATTR_TARGET_*,
279 * this returns the first character's offset and its length.
280 * Otherwise, e.g., the all characters are ATTR_INPUT, this returns
281 * the composition string range because the all is the current target.
283 * aLength can be null (default), but aOffset must not be null.
285 * The aOffset value is offset in the contents. So, when you need offset
286 * in the composition string, you need to subtract mCompositionStart from it.
288 bool GetTargetClauseRange(uint32_t *aOffset, uint32_t *aLength = nullptr);
289 void DispatchTextEvent(nsWindow* aWindow, const nsIMEContext &aIMEContext,
290 bool aCheckAttr = true);
291 already_AddRefed<mozilla::TextRangeArray> CreateTextRangeArray();
293 nsresult EnsureClauseArray(int32_t aCount);
294 nsresult EnsureAttributeArray(int32_t aCount);
297 * When WM_IME_CHAR is received and passed to DefWindowProc, we need to
298 * record the messages. In other words, we should record the messages
299 * when we receive WM_IME_CHAR on windowless plug-in (if we have focus,
300 * we always eat them). When focus is moved from a windowless plug-in to
301 * our window during composition, WM_IME_CHAR messages were received when
302 * the plug-in has focus. However, WM_CHAR messages are received after the
303 * plug-in lost focus. So, we need to ignore the WM_CHAR messages because
304 * they make unexpected text input events on us.
306 nsTArray<MSG> mPassedIMEChar;
308 bool IsIMECharRecordsEmpty()
310 return mPassedIMEChar.IsEmpty();
312 void ResetIMECharRecords()
314 mPassedIMEChar.Clear();
316 void DequeueIMECharRecords(WPARAM &wParam, LPARAM &lParam)
318 MSG msg = mPassedIMEChar.ElementAt(0);
319 wParam = msg.wParam;
320 lParam = msg.lParam;
321 mPassedIMEChar.RemoveElementAt(0);
323 void EnqueueIMECharRecords(WPARAM wParam, LPARAM lParam)
325 MSG msg;
326 msg.wParam = wParam;
327 msg.lParam = lParam;
328 mPassedIMEChar.AppendElement(msg);
331 nsWindow* mComposingWindow;
332 nsString mCompositionString;
333 nsString mLastDispatchedCompositionString;
334 InfallibleTArray<uint32_t> mClauseArray;
335 InfallibleTArray<uint8_t> mAttributeArray;
337 int32_t mCursorPosition;
338 uint32_t mCompositionStart;
340 bool mIsComposing;
341 bool mIsComposingOnPlugin;
342 bool mNativeCaretIsCreated;
344 static UINT sCodePage;
345 static DWORD sIMEProperty;
348 #endif // nsIMM32Handler_h__