1 // Copyright (c) 2012 The Chromium 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 #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WIN_H_ 6 #define UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WIN_H_ 7 8 #include <atlbase.h> 9 #include <atlapp.h> 10 #include <atlcrack.h> 11 #include <atlctrls.h> 12 #include <atlmisc.h> 13 #include <oleacc.h> 14 #include <tom.h> // For ITextDocument, a COM interface to CRichEditCtrl 15 #include <vsstyle.h> 16 17 #include "base/memory/scoped_ptr.h" 18 #include "base/strings/string16.h" 19 #include "base/win/scoped_comptr.h" 20 #include "ui/base/ime/win/tsf_event_router.h" 21 #include "ui/base/models/simple_menu_model.h" 22 #include "ui/base/win/extra_sdk_defines.h" 23 #include "ui/gfx/insets.h" 24 #include "ui/views/controls/textfield/native_textfield_wrapper.h" 25 26 namespace views { 27 28 class MenuRunner; 29 class NativeViewHost; 30 class Textfield; 31 32 static const int kDefaultEditStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | 33 WS_CLIPSIBLINGS; 34 35 // TODO(beng): make a subclass of NativeControlWin instead. 36 class NativeTextfieldWin 37 : public CWindowImpl<NativeTextfieldWin, CRichEditCtrl, 38 CWinTraits<kDefaultEditStyle> >, 39 public CRichEditCommands<NativeTextfieldWin>, 40 public NativeTextfieldWrapper, 41 public ui::SimpleMenuModel::Delegate, 42 public ui::TSFEventRouterObserver { 43 public: 44 DECLARE_WND_SUPERCLASS(L"ViewsTextfieldEdit", MSFTEDIT_CLASS); 45 46 explicit NativeTextfieldWin(Textfield* parent); 47 ~NativeTextfieldWin(); 48 49 // Returns true if the current point is close enough to the origin point in 50 // space and time that it would be considered a double click. 51 VIEWS_EXPORT static bool IsDoubleClick(const POINT& origin, 52 const POINT& current, 53 DWORD elapsed_time); 54 55 // See the code in textfield.cc that calls this for why this is here. 56 void AttachHack(); 57 58 // NativeTextfieldWrapper: 59 virtual string16 GetText() const OVERRIDE; 60 virtual void UpdateText() OVERRIDE; 61 virtual void AppendText(const string16& text) OVERRIDE; 62 virtual void InsertOrReplaceText(const string16& text) OVERRIDE; 63 virtual base::i18n::TextDirection GetTextDirection() const OVERRIDE; 64 virtual string16 GetSelectedText() const OVERRIDE; 65 virtual void SelectAll(bool reversed) OVERRIDE; 66 virtual void ClearSelection() OVERRIDE; 67 virtual void UpdateBorder() OVERRIDE; 68 virtual void UpdateTextColor() OVERRIDE; 69 virtual void UpdateBackgroundColor() OVERRIDE; 70 virtual void UpdateReadOnly() OVERRIDE; 71 virtual void UpdateFont() OVERRIDE; 72 virtual void UpdateIsObscured() OVERRIDE; 73 virtual void UpdateEnabled() OVERRIDE; 74 virtual gfx::Insets CalculateInsets() OVERRIDE; 75 virtual void UpdateHorizontalMargins() OVERRIDE; 76 virtual void UpdateVerticalMargins() OVERRIDE; 77 virtual void UpdateVerticalAlignment() OVERRIDE; 78 virtual bool SetFocus() OVERRIDE; 79 virtual View* GetView() OVERRIDE; 80 virtual gfx::NativeView GetTestingHandle() const OVERRIDE; 81 virtual bool IsIMEComposing() const OVERRIDE; 82 virtual ui::Range GetSelectedRange() const OVERRIDE; 83 virtual void SelectRange(const ui::Range& range) OVERRIDE; 84 virtual gfx::SelectionModel GetSelectionModel() const OVERRIDE; 85 virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE; 86 virtual size_t GetCursorPosition() const OVERRIDE; 87 virtual bool GetCursorEnabled() const OVERRIDE; 88 virtual void SetCursorEnabled(bool enabled) OVERRIDE; 89 virtual bool HandleKeyPressed(const ui::KeyEvent& event) OVERRIDE; 90 virtual bool HandleKeyReleased(const ui::KeyEvent& event) OVERRIDE; 91 virtual void HandleFocus() OVERRIDE; 92 virtual void HandleBlur() OVERRIDE; 93 virtual ui::TextInputClient* GetTextInputClient() OVERRIDE; 94 virtual void SetColor(SkColor value) OVERRIDE; 95 virtual void ApplyColor(SkColor value, const ui::Range& range) OVERRIDE; 96 virtual void SetStyle(gfx::TextStyle style, bool value) OVERRIDE; 97 virtual void ApplyStyle(gfx::TextStyle style, 98 bool value, 99 const ui::Range& range) OVERRIDE; 100 virtual void ClearEditHistory() OVERRIDE; 101 virtual int GetFontHeight() OVERRIDE; 102 virtual int GetTextfieldBaseline() const OVERRIDE; 103 virtual int GetWidthNeededForText() const OVERRIDE; 104 virtual void ExecuteTextCommand(int command_id) OVERRIDE; 105 virtual bool HasTextBeingDragged() OVERRIDE; 106 107 // ui::SimpleMenuModel::Delegate: 108 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; 109 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; 110 virtual bool GetAcceleratorForCommandId( 111 int command_id, 112 ui::Accelerator* accelerator) OVERRIDE; 113 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; 114 115 // ui::TSFEventRouterObserver: 116 virtual void OnTextUpdated(const ui::Range& composition_range) OVERRIDE; 117 virtual void OnTSFStartComposition() OVERRIDE; 118 virtual void OnTSFEndComposition() OVERRIDE; 119 120 // Update accessibility information. 121 void InitializeAccessibilityInfo(); 122 void UpdateAccessibleState(uint32 state_flag, bool set_value); 123 void UpdateAccessibleValue(const string16& value); 124 125 // CWindowImpl 126 BEGIN_MSG_MAP(Edit) 127 MSG_WM_CHAR(OnChar) 128 MSG_WM_CONTEXTMENU(OnContextMenu) 129 MSG_WM_COPY(OnCopy) 130 MSG_WM_CREATE(OnCreate) 131 MSG_WM_CUT(OnCut) 132 MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject) 133 MESSAGE_HANDLER_EX(WM_IME_CHAR, OnImeChar) 134 MESSAGE_HANDLER_EX(WM_IME_STARTCOMPOSITION, OnImeStartComposition) 135 MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition) 136 MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeEndComposition) 137 MESSAGE_HANDLER_EX(WM_POINTERDOWN, OnPointerDown) 138 MSG_WM_KEYDOWN(OnKeyDown) 139 MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk) 140 MSG_WM_LBUTTONDOWN(OnLButtonDown) 141 MSG_WM_LBUTTONUP(OnLButtonUp) 142 MSG_WM_MBUTTONDOWN(OnNonLButtonDown) 143 MSG_WM_MOUSEMOVE(OnMouseMove) 144 MSG_WM_MOUSELEAVE(OnMouseLeave) 145 MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel) 146 MSG_WM_NCCALCSIZE(OnNCCalcSize) 147 MSG_WM_NCPAINT(OnNCPaint) 148 MSG_WM_RBUTTONDOWN(OnNonLButtonDown) 149 MSG_WM_PASTE(OnPaste) 150 MSG_WM_SETFOCUS(OnSetFocus) 151 MSG_WM_KILLFOCUS(OnKillFocus) 152 MSG_WM_SYSCHAR(OnSysChar) // WM_SYSxxx == WM_xxx with ALT down 153 MSG_WM_SYSKEYDOWN(OnKeyDown) 154 END_MSG_MAP() 155 156 private: 157 // This object freezes repainting of the edit until the object is destroyed. 158 // Some methods of the CRichEditCtrl draw synchronously to the screen. If we 159 // don't freeze, the user will see a rapid series of calls to these as 160 // flickers. 161 // 162 // Freezing the control while it is already frozen is permitted; the control 163 // will unfreeze once both freezes are released (the freezes stack). 164 class ScopedFreeze { 165 public: 166 ScopedFreeze(NativeTextfieldWin* edit, ITextDocument* text_object_model); 167 ~ScopedFreeze(); 168 169 private: 170 NativeTextfieldWin* const edit_; 171 ITextDocument* const text_object_model_; 172 173 DISALLOW_COPY_AND_ASSIGN(ScopedFreeze); 174 }; 175 176 // This object suspends placing any operations on the edit's undo stack until 177 // the object is destroyed. If we don't do this, some of the operations we 178 // perform behind the user's back will be undoable by the user, which feels 179 // bizarre and confusing. 180 class ScopedSuspendUndo { 181 public: 182 explicit ScopedSuspendUndo(ITextDocument* text_object_model); 183 ~ScopedSuspendUndo(); 184 185 private: 186 ITextDocument* const text_object_model_; 187 188 DISALLOW_COPY_AND_ASSIGN(ScopedSuspendUndo); 189 }; 190 191 // Message handlers. 192 void OnChar(TCHAR key, UINT repeat_count, UINT flags); 193 void OnContextMenu(HWND window, const POINT& point); 194 void OnCopy(); 195 LRESULT OnCreate(const CREATESTRUCTW* create_struct); 196 void OnCut(); 197 LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam); 198 LRESULT OnImeChar(UINT message, WPARAM wparam, LPARAM lparam); 199 LRESULT OnImeStartComposition(UINT message, WPARAM wparam, LPARAM lparam); 200 LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam); 201 LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam); 202 LRESULT OnPointerDown(UINT message, WPARAM wparam, LPARAM lparam); 203 void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags); 204 void OnLButtonDblClk(UINT keys, const CPoint& point); 205 void OnLButtonDown(UINT keys, const CPoint& point); 206 void OnLButtonUp(UINT keys, const CPoint& point); 207 void OnMouseLeave(); 208 LRESULT OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param); 209 void OnMouseMove(UINT keys, const CPoint& point); 210 int OnNCCalcSize(BOOL w_param, LPARAM l_param); 211 void OnNCPaint(HRGN region); 212 void OnNonLButtonDown(UINT keys, const CPoint& point); 213 void OnPaste(); 214 void OnSetFocus(HWND hwnd); 215 void OnKillFocus(HWND hwnd); 216 void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags); 217 218 // CWindowImpl overrides: 219 virtual void OnFinalMessage(HWND hwnd) OVERRIDE; 220 221 // Helper function for OnChar() and OnKeyDown() that handles keystrokes that 222 // could change the text in the edit. 223 // Note: This function assumes GetCurrentMessage() returns a MSG with 224 // msg > WM_KEYFIRST and < WM_KEYLAST. 225 void HandleKeystroke(); 226 227 // Every piece of code that can change the edit should call these functions 228 // before and after the change. These functions determine if anything 229 // meaningful changed, and do any necessary updating and notification. 230 void OnBeforePossibleChange(); 231 232 // When a user types a BIDI mirroring character (e.g. left parenthesis 233 // U+0028, which should be rendered as '(' in LTR context unless surrounded 234 // by RTL characters in both sides, and it should be rendered as ')' in RTL 235 // context unless surrounded by LTR characters in both sides.), the textfield 236 // does not properly mirror the character when necessary. However, if we 237 // explicitly set the text in the edit to the entire current string, then 238 // the BIDI mirroring characters will be mirrored properly. When 239 // |should_redraw_text| is true, we explicitly set the text in the edit to 240 // the entire current string any time the text changes. 241 void OnAfterPossibleChange(bool should_redraw_text); 242 243 // Given an X coordinate in client coordinates, returns that coordinate 244 // clipped to be within the horizontal bounds of the visible text. 245 // 246 // This is used in our mouse handlers to work around quirky behaviors of the 247 // underlying CRichEditCtrl like not supporting triple-click when the user 248 // doesn't click on the text itself. 249 // 250 // |is_triple_click| should be true iff this is the third click of a triple 251 // click. Sadly, we need to clip slightly differently in this case. 252 LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const; 253 254 // Sets whether the mouse is in the edit. As necessary this redraws the 255 // edit. 256 void SetContainsMouse(bool contains_mouse); 257 258 // Handles composition related works on both IMM32 and TSF implementation. 259 void OnImeStartCompositionInternal(); 260 void OnImeEndCompositionInternal(); 261 262 // Getter for the text_object_model_, used by the ScopedFreeze class. Note 263 // that the pointer returned here is only valid as long as the Edit is still 264 // alive. 265 ITextDocument* GetTextObjectModel() const; 266 267 // Generates the contents of the context menu. 268 void BuildContextMenu(); 269 270 // Returns true if normal processing of the current mouse press event should 271 // occur. 272 bool ShouldProcessMouseEvent(); 273 274 static HMODULE loaded_libarary_module_; 275 276 // The Textfield this object is bound to. 277 Textfield* textfield_; 278 279 // We need to know if the user triple-clicks, so track double click points 280 // and times so we can see if subsequent clicks are actually triple clicks. 281 bool tracking_double_click_; 282 CPoint double_click_point_; 283 DWORD double_click_time_; 284 285 // Used to discard unnecessary WM_MOUSEMOVE events after the first such 286 // unnecessary event. See detailed comments in OnMouseMove(). 287 bool can_discard_mousemove_; 288 289 // The text of this control before a possible change. 290 string16 text_before_change_; 291 292 // If true, the mouse is over the edit. 293 bool contains_mouse_; 294 295 // The contents of the context menu for the edit. 296 scoped_ptr<ui::SimpleMenuModel> context_menu_contents_; 297 scoped_ptr<MenuRunner> context_menu_runner_; 298 299 // Border insets. 300 gfx::Insets content_insets_; 301 302 // This interface is useful for accessing the CRichEditCtrl at a low level. 303 mutable base::win::ScopedComPtr<ITextDocument> text_object_model_; 304 305 // The position and the length of the ongoing composition string. 306 // These values are used for removing a composition string from a search 307 // text to emulate Firefox. 308 bool ime_discard_composition_; 309 int ime_composition_start_; 310 int ime_composition_length_; 311 312 // TODO(beng): remove this when we are a subclass of NativeControlWin. 313 NativeViewHost* container_view_; 314 315 COLORREF bg_color_; 316 317 // The accessibility state of this object. 318 int accessibility_state_; 319 320 scoped_ptr<ui::TSFEventRouter> tsf_event_router_; 321 322 DISALLOW_COPY_AND_ASSIGN(NativeTextfieldWin); 323 }; 324 325 } // namespace views 326 327 #endif // UI_VIEWS_CONTROLS_TEXTFIELD_NATIVE_TEXTFIELD_WIN_H_ 328