| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/vr/content_input_delegate.h" |
| |
| #include "base/callback_helpers.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/vr/platform_input_handler.h" |
| |
| namespace vr { |
| |
| ContentInputDelegate::ContentInputDelegate() {} |
| |
| ContentInputDelegate::ContentInputDelegate(PlatformInputHandler* input_handler) |
| : PlatformUiInputDelegate(input_handler) {} |
| |
| ContentInputDelegate::~ContentInputDelegate() = default; |
| |
| void ContentInputDelegate::OnFocusChanged(bool focused) { |
| // The call below tells the renderer to clear the focused element. Note that |
| // we don't need to do anything when focused is true because the renderer |
| // already knows about the focused element. |
| if (!focused) |
| input_handler()->ClearFocusedElement(); |
| } |
| |
| void ContentInputDelegate::OnWebInputEdited(const EditedText& info, |
| bool commit) { |
| if (!input_handler()) |
| return; |
| |
| last_keyboard_edit_ = info; |
| |
| if (commit) { |
| input_handler()->SubmitWebInput(); |
| return; |
| } |
| |
| input_handler()->OnWebInputEdited(info.GetDiff()); |
| } |
| |
| void ContentInputDelegate::OnSwapContents(int new_content_id) { |
| content_id_ = new_content_id; |
| } |
| |
| void ContentInputDelegate::SendGestureToTarget( |
| std::unique_ptr<InputEvent> event) { |
| if (!event || !input_handler() || ContentGestureIsLocked(event->type())) |
| return; |
| |
| input_handler()->ForwardEventToContent(std::move(event), content_id_); |
| } |
| |
| bool ContentInputDelegate::ContentGestureIsLocked(InputEvent::Type type) { |
| // TODO (asimjour) create a new HoverEnter event when we swap webcontents and |
| // pointer is on the content quad. |
| if (type == InputEvent::kScrollBegin || type == InputEvent::kHoverMove || |
| type == InputEvent::kButtonDown || type == InputEvent::kHoverEnter) |
| locked_content_id_ = content_id_; |
| |
| return locked_content_id_ != content_id_; |
| } |
| |
| void ContentInputDelegate::OnWebInputIndicesChanged( |
| int selection_start, |
| int selection_end, |
| int composition_start, |
| int composition_end, |
| base::OnceCallback<void(const TextInputInfo&)> callback) { |
| // The purpose of this method is to determine if we need to query content for |
| // the text surrounding the currently focused web input field. |
| |
| // If the changed indices match with that from the last keyboard edit, then |
| // this is called in response to the user entering text using the keyboard, so |
| // we already know the text and don't need to ask content for it. |
| TextInputInfo i = last_keyboard_edit_.current; |
| if (i.selection_start == selection_start && |
| i.selection_end == selection_end && |
| i.composition_start == composition_start && |
| i.composition_end == composition_end) { |
| base::ResetAndReturn(&callback).Run(i); |
| return; |
| } |
| |
| // If the changed indices are the same as the previous ones, this is probably |
| // called as a side-effect of us requesting the text state below, so it's safe |
| // to ignore this update. If this is not called as a side-effect of us |
| // requesting the text state below, and the indices just happen to match the |
| // previous state, it's still okay to ignore this update. Consider the |
| // following scenario: 1) State after last request for web input state: |
| // This is a test| |
| // 2) JS on the page changed the web input state to: |
| // This blah test| |
| // In this case, 2) will trigger this function and we'll ignore it. The next |
| // time user types something, we'll calculate the diff from our stale version |
| // of the web input state, but because we're committing the delta between the |
| // previous and the current keyboard state, the update to content will still |
| // be correct. That is, even if the keyboard works with the incorrect version |
| // of the text state, the end result is still correct from the user's point of |
| // view. This is also how android IME works (it only requests text state when |
| // the indices actually change). |
| i = pending_text_input_info_; |
| if (pending_text_request_state_ != kNoPendingRequest && |
| i.selection_start == selection_start && |
| i.selection_end == selection_end && |
| i.composition_start == composition_start && |
| i.composition_end == composition_end) { |
| pending_text_request_state_ = kNoPendingRequest; |
| return; |
| } |
| |
| // The indices changed and we need to query the update state. |
| pending_text_input_info_.selection_start = selection_start; |
| pending_text_input_info_.selection_end = selection_end; |
| pending_text_input_info_.composition_start = composition_start; |
| pending_text_input_info_.composition_end = composition_end; |
| update_state_callbacks_.emplace(std::move(callback)); |
| pending_text_request_state_ = kRequested; |
| input_handler()->RequestWebInputText(base::BindOnce( |
| &ContentInputDelegate::OnWebInputTextChanged, base::Unretained(this))); |
| } |
| |
| void ContentInputDelegate::ClearTextInputState() { |
| pending_text_request_state_ = kNoPendingRequest; |
| pending_text_input_info_ = TextInputInfo(); |
| last_keyboard_edit_ = EditedText(); |
| } |
| |
| void ContentInputDelegate::OnWebInputTextChanged(const base::string16& text) { |
| pending_text_input_info_.text = text; |
| DCHECK(!update_state_callbacks_.empty()); |
| |
| pending_text_request_state_ = kResponseReceived; |
| auto update_state_callback = std::move(update_state_callbacks_.front()); |
| update_state_callbacks_.pop(); |
| base::ResetAndReturn(&update_state_callback).Run(pending_text_input_info_); |
| } |
| |
| } // namespace vr |