15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/find_dialog.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <richedit.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/guid.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/chrome_frame_automation.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxFindChars = 1024; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HHOOK CFFindDialog::msg_hook_ = NULL; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CFFindDialog::CFFindDialog() {} 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CFFindDialog::Init(ChromeFrameAutomationClient* automation_client) { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) automation_client_ = automation_client; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CFFindDialog::OnDestroy(UINT msg, WPARAM wparam, LPARAM lparam, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL& handled) { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In order to cancel the selection when the Find dialog is dismissed, we 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do a fake search for a string that is unlikely to appear on the page. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(robertshield): Change this to plumb through a StopFinding automation 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // message that triggers a ViewMsg_StopFinding. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string guid(base::GenerateGUID()); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) automation_client_->FindInPage(ASCIIToWide(guid), FWD, CASE_SENSITIVE, false); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UninstallMessageHook(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CFFindDialog::OnFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL& bHandled) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 find_text(kMaxFindChars, L'\0'); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) find_text.resize(GetDlgItemText(IDC_FIND_TEXT, &find_text[0], kMaxFindChars)); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repeated searches for the same string should move to the next instance. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool find_next = (find_text == last_find_text_); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!find_next) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_find_text_ = find_text; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool match_case = IsDlgButtonChecked(IDC_MATCH_CASE) == BST_CHECKED; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool search_down = IsDlgButtonChecked(IDC_DIRECTION_DOWN) == BST_CHECKED; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) automation_client_->FindInPage(find_text, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) search_down ? FWD : BACK, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match_case ? CASE_SENSITIVE : IGNORE_CASE, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) find_next); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CFFindDialog::OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL& bHandled) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DestroyWindow(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CFFindDialog::OnInitDialog(UINT msg, WPARAM wparam, LPARAM lparam, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL& handled) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Init() must be called before Create() or DoModal()! 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(automation_client_.get()); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallMessageHook(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDlgItemMessage(IDC_FIND_TEXT, EM_EXLIMITTEXT, 0, kMaxFindChars); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL result = CheckRadioButton(IDC_DIRECTION_DOWN, IDC_DIRECTION_UP, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDC_DIRECTION_DOWN); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HWND text_field = GetDlgItem(IDC_FIND_TEXT); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::SetFocus(text_field); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; // we set the focus ourselves. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CALLBACK CFFindDialog::GetMsgProc(int code, WPARAM wparam, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPARAM lparam) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mostly borrowed from http://support.microsoft.com/kb/q187988/ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and http://www.codeproject.com/KB/atl/cdialogmessagehook.aspx. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LPMSG msg = reinterpret_cast<LPMSG>(lparam); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (code >= 0 && wparam == PM_REMOVE && 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg->message >= WM_KEYFIRST && msg->message <= WM_KEYLAST) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HWND hwnd = GetActiveWindow(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (::IsWindow(hwnd) && ::IsDialogMessage(hwnd, msg)) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The value returned from this hookproc is ignored, and it cannot 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be used to tell Windows the message has been handled. To avoid 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // further processing, convert the message to WM_NULL before 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // returning. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg->hwnd = NULL; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg->message = WM_NULL; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg->lParam = 0L; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg->wParam = 0; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Passes the hook information to the next hook procedure in 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the current hook chain. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ::CallNextHookEx(msg_hook_, code, wparam, lparam); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CFFindDialog::InstallMessageHook() { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure we only call this once. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(msg_hook_ == NULL); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg_hook_ = ::SetWindowsHookEx(WH_GETMESSAGE, &CFFindDialog::GetMsgProc, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _AtlBaseModule.m_hInst, GetCurrentThreadId()); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(msg_hook_ != NULL); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return msg_hook_ != NULL; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CFFindDialog::UninstallMessageHook() { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(msg_hook_ != NULL); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL result = ::UnhookWindowsHookEx(msg_hook_); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) msg_hook_ = NULL; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result != FALSE; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 121