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