Mac: Add IME support with off-screen rendering (issue #973).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1259 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
3f17635d3e
commit
ac4c19159c
3
cef.gyp
3
cef.gyp
|
@ -1038,8 +1038,11 @@
|
|||
'libcef/browser/javascript_dialog_mac.mm',
|
||||
'libcef/browser/menu_creator_runner_mac.h',
|
||||
'libcef/browser/menu_creator_runner_mac.mm',
|
||||
'libcef/browser/render_widget_host_view_osr_mac.mm',
|
||||
'libcef/browser/render_widget_host_view_osr.cc',
|
||||
'libcef/browser/render_widget_host_view_osr.h',
|
||||
'libcef/browser/text_input_client_osr_mac.mm',
|
||||
'libcef/browser/text_input_client_osr_mac.h',
|
||||
'libcef/browser/web_contents_view_osr.cc',
|
||||
'libcef/browser/web_contents_view_osr.h',
|
||||
# Include sources for context menu implementation.
|
||||
|
|
|
@ -407,6 +407,26 @@ typedef struct _cef_browser_host_t {
|
|||
///
|
||||
void (CEF_CALLBACK *send_capture_lost_event)(
|
||||
struct _cef_browser_host_t* self);
|
||||
|
||||
///
|
||||
// Get the NSTextInputContext implementation for enabling IME on Mac when
|
||||
// window rendering is disabled.
|
||||
///
|
||||
cef_text_input_context_t (CEF_CALLBACK *get_nstext_input_context)(
|
||||
struct _cef_browser_host_t* self);
|
||||
|
||||
///
|
||||
// Handles a keyDown event prior to passing it through the NSTextInputClient
|
||||
// machinery.
|
||||
///
|
||||
void (CEF_CALLBACK *handle_key_event_before_text_input_client)(
|
||||
struct _cef_browser_host_t* self, cef_event_handle_t keyEvent);
|
||||
|
||||
///
|
||||
// Performs any additional actions after NSTextInputClient handles the event.
|
||||
///
|
||||
void (CEF_CALLBACK *handle_key_event_after_text_input_client)(
|
||||
struct _cef_browser_host_t* self, cef_event_handle_t keyEvent);
|
||||
} cef_browser_host_t;
|
||||
|
||||
|
||||
|
|
|
@ -452,6 +452,27 @@ class CefBrowserHost : public virtual CefBase {
|
|||
///
|
||||
/*--cef()--*/
|
||||
virtual void SendCaptureLostEvent() =0;
|
||||
|
||||
///
|
||||
// Get the NSTextInputContext implementation for enabling IME on Mac when
|
||||
// window rendering is disabled.
|
||||
///
|
||||
/*--cef(default_retval=NULL)--*/
|
||||
virtual CefTextInputContext GetNSTextInputContext() =0;
|
||||
|
||||
///
|
||||
// Handles a keyDown event prior to passing it through the NSTextInputClient
|
||||
// machinery.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent) =0;
|
||||
|
||||
///
|
||||
// Performs any additional actions after NSTextInputClient handles the event.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent) =0;
|
||||
|
||||
};
|
||||
|
||||
#endif // CEF_INCLUDE_CEF_BROWSER_H_
|
||||
|
|
|
@ -72,6 +72,7 @@ class CefCriticalSection {
|
|||
#define CefCursorHandle cef_cursor_handle_t
|
||||
#define CefEventHandle cef_event_handle_t
|
||||
#define CefWindowHandle cef_window_handle_t
|
||||
#define CefTextInputContext cef_text_input_context_t
|
||||
|
||||
struct CefMainArgsTraits {
|
||||
typedef cef_main_args_t struct_type;
|
||||
|
|
|
@ -72,6 +72,7 @@ class CefCriticalSection {
|
|||
#define CefCursorHandle cef_cursor_handle_t
|
||||
#define CefEventHandle cef_event_handle_t
|
||||
#define CefWindowHandle cef_window_handle_t
|
||||
#define CefTextInputContext cef_text_input_context_t
|
||||
|
||||
struct CefMainArgsTraits {
|
||||
typedef cef_main_args_t struct_type;
|
||||
|
|
|
@ -46,6 +46,7 @@ extern "C" {
|
|||
#define cef_cursor_handle_t void*
|
||||
#define cef_event_handle_t GdkEvent*
|
||||
#define cef_window_handle_t GtkWidget*
|
||||
#define cef_text_input_context_t void*
|
||||
|
||||
///
|
||||
// Structure representing CefExecuteProcess arguments.
|
||||
|
|
|
@ -43,18 +43,22 @@
|
|||
@class NSCursor;
|
||||
@class NSEvent;
|
||||
@class NSView;
|
||||
@class NSTextInputContext;
|
||||
#else
|
||||
class NSCursor;
|
||||
class NSEvent;
|
||||
struct NSView;
|
||||
class NSTextInputContext;
|
||||
#endif
|
||||
#define cef_cursor_handle_t NSCursor*
|
||||
#define cef_event_handle_t NSEvent*
|
||||
#define cef_window_handle_t NSView*
|
||||
#define cef_text_input_context_t NSTextInputContext*
|
||||
#else
|
||||
#define cef_cursor_handle_t void*
|
||||
#define cef_event_handle_t void*
|
||||
#define cef_window_handle_t void*
|
||||
#define cef_text_input_context_t void*
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -46,6 +46,7 @@ extern "C" {
|
|||
#define cef_cursor_handle_t HCURSOR
|
||||
#define cef_event_handle_t MSG*
|
||||
#define cef_window_handle_t HWND
|
||||
#define cef_text_input_context_t void*
|
||||
|
||||
///
|
||||
// Structure representing CefExecuteProcess arguments.
|
||||
|
|
|
@ -71,6 +71,7 @@ class CefCriticalSection {
|
|||
#define CefCursorHandle cef_cursor_handle_t
|
||||
#define CefEventHandle cef_event_handle_t
|
||||
#define CefWindowHandle cef_window_handle_t
|
||||
#define CefTextInputContext cef_text_input_context_t
|
||||
|
||||
struct CefMainArgsTraits {
|
||||
typedef cef_main_args_t struct_type;
|
||||
|
|
|
@ -1453,6 +1453,22 @@ void CefBrowserHostImpl::RunFileChooser(
|
|||
callback));
|
||||
}
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() {
|
||||
NOTREACHED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
NOTREACHED();
|
||||
}
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
// content::WebContentsDelegate methods.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -143,6 +143,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
int deltaX, int deltaY) OVERRIDE;
|
||||
virtual void SendFocusEvent(bool setFocus) OVERRIDE;
|
||||
virtual void SendCaptureLostEvent() OVERRIDE;
|
||||
virtual CefTextInputContext GetNSTextInputContext() OVERRIDE;
|
||||
virtual void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent)
|
||||
OVERRIDE;
|
||||
virtual void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent)
|
||||
OVERRIDE;
|
||||
|
||||
// CefBrowser methods.
|
||||
virtual CefRefPtr<CefBrowserHost> GetHost() OVERRIDE;
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
||||
#include "libcef/browser/render_widget_host_view_osr.h"
|
||||
#include "libcef/browser/text_input_client_osr_mac.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/string_util.h"
|
||||
|
@ -252,6 +256,59 @@ bool RunSaveFileDialog(const content::FileChooserParams& params,
|
|||
|
||||
} // namespace
|
||||
|
||||
CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() {
|
||||
if (!IsWindowRenderingDisabled()) {
|
||||
NOTREACHED() << "Window rendering is not disabled";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
NOTREACHED() << "Called on invalid thread";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
|
||||
GetWebContents()->GetRenderWidgetHostView());
|
||||
|
||||
return rwhv->GetNSTextInputContext();
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
if (!IsWindowRenderingDisabled()) {
|
||||
NOTREACHED() << "Window rendering is not disabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
NOTREACHED() << "Called on invalid thread";
|
||||
return;
|
||||
}
|
||||
|
||||
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
|
||||
GetWebContents()->GetRenderWidgetHostView());
|
||||
|
||||
rwhv->HandleKeyEventBeforeTextInputClient(keyEvent);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
if (!IsWindowRenderingDisabled()) {
|
||||
NOTREACHED() << "Window rendering is not disabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CEF_CURRENTLY_ON_UIT()) {
|
||||
NOTREACHED() << "Called on invalid thread";
|
||||
return;
|
||||
}
|
||||
|
||||
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
|
||||
GetWebContents()->GetRenderWidgetHostView());
|
||||
|
||||
rwhv->HandleKeyEventAfterTextInputClient(keyEvent);
|
||||
}
|
||||
|
||||
bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
|
|
|
@ -52,7 +52,11 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
|
|||
render_widget_host_(content::RenderWidgetHostImpl::From(widget)),
|
||||
parent_host_view_(NULL),
|
||||
popup_host_view_(NULL),
|
||||
about_to_validate_and_paint_(false) {
|
||||
about_to_validate_and_paint_(false)
|
||||
#if defined(OS_MACOSX)
|
||||
, text_input_context_osr_mac_(NULL)
|
||||
#endif
|
||||
{
|
||||
DCHECK(render_widget_host_);
|
||||
render_widget_host_->SetView(this);
|
||||
|
||||
|
@ -204,6 +208,7 @@ void CefRenderWidgetHostViewOSR::UpdateCursor(const WebCursor& cursor) {
|
|||
void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) {
|
||||
}
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
void CefRenderWidgetHostViewOSR::TextInputStateChanged(
|
||||
const ViewHostMsg_TextInputState_Params& params) {
|
||||
}
|
||||
|
@ -215,6 +220,7 @@ void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged(
|
|||
const ui::Range& range,
|
||||
const std::vector<gfx::Rect>& character_bounds) {
|
||||
}
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
void CefRenderWidgetHostViewOSR::DidUpdateBackingStore(
|
||||
const gfx::Rect& scroll_rect,
|
||||
|
|
|
@ -42,6 +42,37 @@ class CefWebContentsViewOSR;
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase {
|
||||
#if defined(OS_MACOSX)
|
||||
public:
|
||||
NSTextInputContext* GetNSTextInputContext();
|
||||
void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent);
|
||||
void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent);
|
||||
|
||||
bool GetCachedFirstRectForCharacterRange(ui::Range range, gfx::Rect* rect,
|
||||
ui::Range* actual_range) const;
|
||||
|
||||
private:
|
||||
// Returns composition character boundary rectangle. The |range| is
|
||||
// composition based range. Also stores |actual_range| which is corresponding
|
||||
// to actually used range for returned rectangle.
|
||||
gfx::Rect GetFirstRectForCompositionRange(const ui::Range& range,
|
||||
ui::Range* actual_range) const;
|
||||
|
||||
// Converts from given whole character range to composition oriented range. If
|
||||
// the conversion failed, return ui::Range::InvalidRange.
|
||||
ui::Range ConvertCharacterRangeToCompositionRange(
|
||||
const ui::Range& request_range) const;
|
||||
|
||||
// Returns true if there is line break in |range| and stores line breaking
|
||||
// point to |line_breaking_point|. The |line_break_point| is valid only if
|
||||
// this function returns true.
|
||||
static bool GetLineBreakIndex(const std::vector<gfx::Rect>& bounds,
|
||||
const ui::Range& range,
|
||||
size_t* line_break_point);
|
||||
|
||||
void DestroyNSTextInputOSR();
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
public:
|
||||
// RenderWidgetHostView methods.
|
||||
virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
|
||||
|
@ -170,6 +201,8 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase {
|
|||
void NotifyHideWidget();
|
||||
void NotifySizeWidget();
|
||||
|
||||
content::RenderWidgetHostImpl* get_render_widget_host_impl() const
|
||||
{ return render_widget_host_; }
|
||||
CefRefPtr<CefBrowserHostImpl> get_browser_impl() const;
|
||||
void set_browser_impl(CefRefPtr<CefBrowserHostImpl> browser);
|
||||
void set_popup_host_view(CefRenderWidgetHostViewOSR* popup_view);
|
||||
|
@ -205,6 +238,10 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase {
|
|||
|
||||
gfx::Rect popup_position_;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
NSTextInputContext* text_input_context_osr_mac_;
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CefRenderWidgetHostViewOSR);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
// Copyright (c) 2013 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2011 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 "libcef/browser/render_widget_host_view_osr.h"
|
||||
#include "libcef/browser/text_input_client_osr_mac.h"
|
||||
|
||||
static CefTextInputClientOSRMac* GetInputClientFromContext(
|
||||
const NSTextInputContext* context) {
|
||||
if (!context)
|
||||
return NULL;
|
||||
return reinterpret_cast<CefTextInputClientOSRMac*>([context client]);
|
||||
}
|
||||
|
||||
CefTextInputContext CefRenderWidgetHostViewOSR::GetNSTextInputContext() {
|
||||
if (!text_input_context_osr_mac_) {
|
||||
CefTextInputClientOSRMac* text_input_client_osr_mac =
|
||||
[[CefTextInputClientOSRMac alloc] initWithRenderWidgetHostViewOSR:
|
||||
this];
|
||||
|
||||
text_input_context_osr_mac_ = [[NSTextInputContext alloc] initWithClient:
|
||||
text_input_client_osr_mac];
|
||||
}
|
||||
|
||||
return text_input_context_osr_mac_;
|
||||
}
|
||||
|
||||
void CefRenderWidgetHostViewOSR::HandleKeyEventBeforeTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
if (client)
|
||||
[client HandleKeyEventBeforeTextInputClient: keyEvent];
|
||||
}
|
||||
|
||||
void CefRenderWidgetHostViewOSR::HandleKeyEventAfterTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
if (client)
|
||||
[client HandleKeyEventAfterTextInputClient: keyEvent];
|
||||
}
|
||||
|
||||
void CefRenderWidgetHostViewOSR::DestroyNSTextInputOSR() {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
if (client) {
|
||||
[client release];
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
[text_input_context_osr_mac_ release];
|
||||
text_input_context_osr_mac_ = NULL;
|
||||
}
|
||||
|
||||
void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged(
|
||||
const ui::Range& range,
|
||||
const std::vector<gfx::Rect>& character_bounds) {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
client->markedRange_ = range.ToNSRange();
|
||||
client->composition_range_ = range;
|
||||
client->composition_bounds_ = character_bounds;
|
||||
}
|
||||
|
||||
void CefRenderWidgetHostViewOSR::ImeCancelComposition() {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
if (client)
|
||||
[client cancelComposition];
|
||||
}
|
||||
|
||||
void CefRenderWidgetHostViewOSR::TextInputStateChanged(
|
||||
const ViewHostMsg_TextInputState_Params& params) {
|
||||
[NSApp updateWindows];
|
||||
}
|
||||
|
||||
bool CefRenderWidgetHostViewOSR::GetLineBreakIndex(
|
||||
const std::vector<gfx::Rect>& bounds,
|
||||
const ui::Range& range,
|
||||
size_t* line_break_point) {
|
||||
DCHECK(line_break_point);
|
||||
if (range.start() >= bounds.size() || range.is_reversed() || range.is_empty())
|
||||
return false;
|
||||
|
||||
// We can't check line breaking completely from only rectangle array. Thus we
|
||||
// assume the line breaking as the next character's y offset is larger than
|
||||
// a threshold. Currently the threshold is determined as minimum y offset plus
|
||||
// 75% of maximum height.
|
||||
const size_t loop_end_idx = std::min(bounds.size(), range.end());
|
||||
int max_height = 0;
|
||||
int min_y_offset = kint32max;
|
||||
for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
|
||||
max_height = std::max(max_height, bounds[idx].height());
|
||||
min_y_offset = std::min(min_y_offset, bounds[idx].y());
|
||||
}
|
||||
int line_break_threshold = min_y_offset + (max_height * 3 / 4);
|
||||
for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
|
||||
if (bounds[idx].y() > line_break_threshold) {
|
||||
*line_break_point = idx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::Rect CefRenderWidgetHostViewOSR::GetFirstRectForCompositionRange(
|
||||
const ui::Range& range, ui::Range* actual_range) const {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
|
||||
DCHECK(client);
|
||||
DCHECK(actual_range);
|
||||
DCHECK(!client->composition_bounds_.empty());
|
||||
DCHECK_LE(range.start(), client->composition_bounds_.size());
|
||||
DCHECK_LE(range.end(), client->composition_bounds_.size());
|
||||
|
||||
if (range.is_empty()) {
|
||||
*actual_range = range;
|
||||
if (range.start() == client->composition_bounds_.size()) {
|
||||
return gfx::Rect(client->composition_bounds_[range.start() - 1].right(),
|
||||
client->composition_bounds_[range.start() - 1].y(),
|
||||
0,
|
||||
client->composition_bounds_[range.start() - 1].height());
|
||||
} else {
|
||||
return gfx::Rect(client->composition_bounds_[range.start()].x(),
|
||||
client->composition_bounds_[range.start()].y(),
|
||||
0,
|
||||
client->composition_bounds_[range.start()].height());
|
||||
}
|
||||
}
|
||||
|
||||
size_t end_idx;
|
||||
if (!GetLineBreakIndex(client->composition_bounds_,
|
||||
range, &end_idx)) {
|
||||
end_idx = range.end();
|
||||
}
|
||||
*actual_range = ui::Range(range.start(), end_idx);
|
||||
gfx::Rect rect = client->composition_bounds_[range.start()];
|
||||
for (size_t i = range.start() + 1; i < end_idx; ++i) {
|
||||
rect.Union(client->composition_bounds_[i]);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
ui::Range CefRenderWidgetHostViewOSR::ConvertCharacterRangeToCompositionRange(
|
||||
const ui::Range& request_range) const {
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
DCHECK(client);
|
||||
|
||||
if (client->composition_range_.is_empty())
|
||||
return ui::Range::InvalidRange();
|
||||
|
||||
if (request_range.is_reversed())
|
||||
return ui::Range::InvalidRange();
|
||||
|
||||
if (request_range.start() < client->composition_range_.start()
|
||||
|| request_range.start() > client->composition_range_.end()
|
||||
|| request_range.end() > client->composition_range_.end())
|
||||
return ui::Range::InvalidRange();
|
||||
|
||||
return ui::Range(request_range.start() - client->composition_range_.start(),
|
||||
request_range.end() - client->composition_range_.start());
|
||||
}
|
||||
|
||||
bool CefRenderWidgetHostViewOSR::GetCachedFirstRectForCharacterRange(
|
||||
ui::Range range, gfx::Rect* rect, ui::Range* actual_range) const {
|
||||
DCHECK(rect);
|
||||
CefTextInputClientOSRMac* client = GetInputClientFromContext(
|
||||
text_input_context_osr_mac_);
|
||||
|
||||
// If requested range is same as caret location, we can just return it.
|
||||
if (selection_range_.is_empty() && ui::Range(range) == selection_range_) {
|
||||
if (actual_range)
|
||||
*actual_range = range;
|
||||
*rect = client->caret_rect_;
|
||||
return true;
|
||||
}
|
||||
|
||||
const ui::Range request_range_in_composition =
|
||||
ConvertCharacterRangeToCompositionRange(ui::Range(range));
|
||||
if (request_range_in_composition == ui::Range::InvalidRange())
|
||||
return false;
|
||||
|
||||
// If firstRectForCharacterRange in WebFrame is failed in renderer,
|
||||
// ImeCompositionRangeChanged will be sent with empty vector.
|
||||
if (client->composition_bounds_.empty())
|
||||
return false;
|
||||
|
||||
DCHECK_EQ(client->composition_bounds_.size(),
|
||||
client->composition_range_.length());
|
||||
|
||||
ui::Range ui_actual_range;
|
||||
*rect = GetFirstRectForCompositionRange(request_range_in_composition,
|
||||
&ui_actual_range);
|
||||
if (actual_range) {
|
||||
*actual_range = ui::Range(
|
||||
client->composition_range_.start() + ui_actual_range.start(),
|
||||
client->composition_range_.start() + ui_actual_range.end()).ToNSRange();
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
|
||||
#define CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
|
||||
#pragma once
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <vector>
|
||||
|
||||
#include "libcef/browser/render_widget_host_view_osr.h"
|
||||
|
||||
#include "base/memory/scoped_nsobject.h"
|
||||
#include "base/string16.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
||||
#include "content/common/edit_command.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h"
|
||||
|
||||
// Implementation for the NSTextInputClient protocol used for enabling IME on
|
||||
// mac when window rendering is disabled.
|
||||
|
||||
@interface CefTextInputClientOSRMac : NSObject<NSTextInputClient> {
|
||||
|
||||
@public
|
||||
// The range of current marked text inside the whole content of the DOM node
|
||||
// being edited.
|
||||
NSRange markedRange_;
|
||||
|
||||
// The current composition character range and its bounds.
|
||||
ui::Range composition_range_;
|
||||
std::vector<gfx::Rect> composition_bounds_;
|
||||
|
||||
// The current caret bounds.
|
||||
gfx::Rect caret_rect_;
|
||||
|
||||
@private
|
||||
// Represents the input-method attributes supported by this object.
|
||||
scoped_nsobject<NSArray> validAttributesForMarkedText_;
|
||||
|
||||
// Indicates if we are currently handling a key down event.
|
||||
BOOL handlingKeyDown_;
|
||||
|
||||
// Indicates if there is any marked text.
|
||||
BOOL hasMarkedText_;
|
||||
|
||||
// Indicates whether there was any marked text prior to handling
|
||||
// the current key event.
|
||||
BOOL oldHasMarkedText_;
|
||||
|
||||
// Indicates if unmarkText is called or not when handling a keyboard
|
||||
// event.
|
||||
BOOL unmarkTextCalled_;
|
||||
|
||||
// The selected range, cached from a message sent by the renderer.
|
||||
NSRange selectedRange_;
|
||||
|
||||
// Text to be inserted which was generated by handling a key down event.
|
||||
string16 textToBeInserted_;
|
||||
|
||||
// Marked text which was generated by handling a key down event.
|
||||
string16 markedText_;
|
||||
|
||||
// Underline information of the |markedText_|.
|
||||
std::vector<WebKit::WebCompositionUnderline> underlines_;
|
||||
|
||||
// Indicates if doCommandBySelector method receives any edit command when
|
||||
// handling a key down event.
|
||||
BOOL hasEditCommands_;
|
||||
|
||||
// Contains edit commands received by the -doCommandBySelector: method when
|
||||
// handling a key down event, not including inserting commands, eg. insertTab,
|
||||
// etc.
|
||||
content::EditCommands editCommands_;
|
||||
|
||||
CefRenderWidgetHostViewOSR* renderWidgetHostView_;
|
||||
}
|
||||
|
||||
@property(nonatomic, readonly) NSRange selectedRange;
|
||||
@property(nonatomic) BOOL handlingKeyDown;
|
||||
|
||||
- (id)initWithRenderWidgetHostViewOSR:(CefRenderWidgetHostViewOSR*) rwhv;
|
||||
- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent;
|
||||
- (void)HandleKeyEventAfterTextInputClient:(NSEvent*)keyEvent;
|
||||
- (void)cancelComposition;
|
||||
|
||||
@end
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
|
|
@ -0,0 +1,363 @@
|
|||
// Copyright (c) 2013 The Chromium Embedded Framework 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 "libcef/browser/text_input_client_osr_mac.h"
|
||||
#include "libcef/browser/browser_host_impl.h"
|
||||
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
|
||||
#import "content/browser/renderer_host/text_input_client_mac.h"
|
||||
#include "content/common/input_messages.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Maximum number of characters we allow in a tooltip.
|
||||
const size_t kMaxTooltipLength = 1024;
|
||||
|
||||
// TODO(suzhe): Upstream this function.
|
||||
WebKit::WebColor WebColorFromNSColor(NSColor *color) {
|
||||
CGFloat r, g, b, a;
|
||||
[color getRed:&r green:&g blue:&b alpha:&a];
|
||||
|
||||
return
|
||||
std::max(0, std::min(static_cast<int>(lroundf(255.0f * a)), 255)) << 24 |
|
||||
std::max(0, std::min(static_cast<int>(lroundf(255.0f * r)), 255)) << 16 |
|
||||
std::max(0, std::min(static_cast<int>(lroundf(255.0f * g)), 255)) << 8 |
|
||||
std::max(0, std::min(static_cast<int>(lroundf(255.0f * b)), 255));
|
||||
}
|
||||
|
||||
// Extract underline information from an attributed string. Mostly copied from
|
||||
// third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm
|
||||
void ExtractUnderlines(NSAttributedString* string,
|
||||
std::vector<WebKit::WebCompositionUnderline>* underlines) {
|
||||
int length = [[string string] length];
|
||||
int i = 0;
|
||||
while (i < length) {
|
||||
NSRange range;
|
||||
NSDictionary* attrs = [string attributesAtIndex:i
|
||||
longestEffectiveRange:&range
|
||||
inRange:NSMakeRange(i, length - i)];
|
||||
NSNumber *style = [attrs objectForKey: NSUnderlineStyleAttributeName];
|
||||
if (style) {
|
||||
WebKit::WebColor color = SK_ColorBLACK;
|
||||
if (NSColor *colorAttr =
|
||||
[attrs objectForKey:NSUnderlineColorAttributeName]) {
|
||||
color = WebColorFromNSColor(
|
||||
[colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
|
||||
}
|
||||
underlines->push_back(WebKit::WebCompositionUnderline(
|
||||
range.location, NSMaxRange(range), color, [style intValue] > 1));
|
||||
}
|
||||
i = range.location + range.length;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
extern NSString* NSTextInputReplacementRangeAttributeName;
|
||||
}
|
||||
|
||||
@implementation CefTextInputClientOSRMac
|
||||
|
||||
@synthesize selectedRange = selectedRange_;
|
||||
@synthesize handlingKeyDown = handlingKeyDown_;
|
||||
|
||||
- (id)initWithRenderWidgetHostViewOSR:(CefRenderWidgetHostViewOSR*)rwhv {
|
||||
self = [super init];
|
||||
renderWidgetHostView_ = rwhv;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray*)validAttributesForMarkedText {
|
||||
if (!validAttributesForMarkedText_) {
|
||||
validAttributesForMarkedText_.reset([[NSArray alloc] initWithObjects:
|
||||
NSUnderlineStyleAttributeName,
|
||||
NSUnderlineColorAttributeName,
|
||||
NSMarkedClauseSegmentAttributeName,
|
||||
NSTextInputReplacementRangeAttributeName,
|
||||
nil]);
|
||||
}
|
||||
return validAttributesForMarkedText_.get();
|
||||
}
|
||||
|
||||
- (NSRange)markedRange {
|
||||
return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
|
||||
- (BOOL)hasMarkedText {
|
||||
return hasMarkedText_;
|
||||
}
|
||||
|
||||
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
|
||||
BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
|
||||
NSString* im_text = isAttributedString ? [aString string] : aString;
|
||||
if (handlingKeyDown_) {
|
||||
textToBeInserted_.append(base::SysNSStringToUTF16(im_text));
|
||||
} else {
|
||||
ui::Range replacement_range(replacementRange);
|
||||
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->ImeConfirmComposition(
|
||||
base::SysNSStringToUTF16(im_text), replacement_range);
|
||||
}
|
||||
|
||||
// Inserting text will delete all marked text automatically.
|
||||
hasMarkedText_ = NO;
|
||||
}
|
||||
|
||||
- (void)doCommandBySelector:(SEL)aSelector {
|
||||
// An input method calls this function to dispatch an editing command to be
|
||||
// handled by this view.
|
||||
if (aSelector == @selector(noop:))
|
||||
return;
|
||||
std::string command([content::RenderWidgetHostViewMacEditCommandHelper::
|
||||
CommandNameForSelector(aSelector) UTF8String]);
|
||||
|
||||
// If this method is called when handling a key down event, then we need to
|
||||
// handle the command in the key event handler. Otherwise we can just handle
|
||||
// it here.
|
||||
if (handlingKeyDown_) {
|
||||
hasEditCommands_ = YES;
|
||||
// We ignore commands that insert characters, because this was causing
|
||||
// strange behavior (e.g. tab always inserted a tab rather than moving to
|
||||
// the next field on the page).
|
||||
if (!StartsWithASCII(command, "insert", false))
|
||||
editCommands_.push_back(content::EditCommand(command, ""));
|
||||
} else {
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->Send(
|
||||
new InputMsg_ExecuteEditCommand(
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->
|
||||
GetRoutingID(), command, ""));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelRange
|
||||
replacementRange:(NSRange)replacementRange {
|
||||
// An input method updates the composition string.
|
||||
// We send the given text and range to the renderer so it can update the
|
||||
// composition node of WebKit.
|
||||
|
||||
BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
|
||||
NSString* im_text = isAttributedString ? [aString string] : aString;
|
||||
int length = [im_text length];
|
||||
|
||||
// |markedRange_| will get set on a callback from ImeSetComposition().
|
||||
selectedRange_ = newSelRange;
|
||||
markedText_ = base::SysNSStringToUTF16(im_text);
|
||||
hasMarkedText_ = (length > 0);
|
||||
underlines_.clear();
|
||||
|
||||
if (isAttributedString) {
|
||||
ExtractUnderlines(aString, &underlines_);
|
||||
} else {
|
||||
// Use a thin black underline by default.
|
||||
underlines_.push_back(WebKit::WebCompositionUnderline(0, length,
|
||||
SK_ColorBLACK, false));
|
||||
}
|
||||
|
||||
// If we are handling a key down event, then SetComposition() will be
|
||||
// called in keyEvent: method.
|
||||
// Input methods of Mac use setMarkedText calls with an empty text to cancel
|
||||
// an ongoing composition. So, we should check whether or not the given text
|
||||
// is empty to update the input method state. (Our input method backend can
|
||||
// automatically cancels an ongoing composition when we send an empty text.
|
||||
// So, it is OK to send an empty text to the renderer.)
|
||||
if (!handlingKeyDown_) {
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->ImeSetComposition(
|
||||
markedText_, underlines_, newSelRange.location,
|
||||
NSMaxRange(newSelRange));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unmarkText {
|
||||
// Delete the composition node of the renderer and finish an ongoing
|
||||
// composition.
|
||||
// It seems an input method calls the setMarkedText method and set an empty
|
||||
// text when it cancels an ongoing composition, i.e. I have never seen an
|
||||
// input method calls this method.
|
||||
hasMarkedText_ = NO;
|
||||
markedText_.clear();
|
||||
underlines_.clear();
|
||||
|
||||
// If we are handling a key down event, then ConfirmComposition() will be
|
||||
// called in keyEvent: method.
|
||||
if (!handlingKeyDown_) {
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->
|
||||
ImeConfirmComposition();
|
||||
} else {
|
||||
unmarkTextCalled_ = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range
|
||||
actualRange:(NSRangePointer)actualRange {
|
||||
if (actualRange)
|
||||
*actualRange = range;
|
||||
NSAttributedString* str = content::TextInputClientMac::GetInstance()->
|
||||
GetAttributedSubstringFromRange(
|
||||
renderWidgetHostView_->GetRenderWidgetHost(), range);
|
||||
return str;
|
||||
}
|
||||
|
||||
- (NSRect)firstViewRectForCharacterRange:(NSRange)theRange
|
||||
actualRange:(NSRangePointer)actualRange {
|
||||
NSRect rect;
|
||||
gfx::Rect gfxRect;
|
||||
ui::Range range(theRange);
|
||||
ui::Range actual_range;
|
||||
if (!renderWidgetHostView_->GetCachedFirstRectForCharacterRange(range,
|
||||
&gfxRect, &actual_range)) {
|
||||
rect = content::TextInputClientMac::GetInstance()->
|
||||
GetFirstRectForRange(renderWidgetHostView_->GetRenderWidgetHost(),
|
||||
range.ToNSRange());
|
||||
|
||||
if (actualRange)
|
||||
*actualRange = range.ToNSRange();
|
||||
} else {
|
||||
rect = NSRectFromCGRect(gfxRect.ToCGRect());
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (NSRect) screenRectFromViewRect:(NSRect)rect {
|
||||
NSRect screenRect;
|
||||
|
||||
int screenX, screenY;
|
||||
renderWidgetHostView_->get_browser_impl()->GetClient()->GetRenderHandler()->
|
||||
GetScreenPoint(renderWidgetHostView_->get_browser_impl()->GetBrowser(),
|
||||
rect.origin.x, rect.origin.y, screenX, screenY);
|
||||
screenRect.origin = NSMakePoint(screenX, screenY);
|
||||
screenRect.size = rect.size;
|
||||
|
||||
return screenRect;
|
||||
}
|
||||
|
||||
- (NSRect)firstRectForCharacterRange:(NSRange)theRange
|
||||
actualRange:(NSRangePointer)actualRange {
|
||||
NSRect rect = [self firstViewRectForCharacterRange:theRange
|
||||
actualRange:actualRange];
|
||||
|
||||
// Convert into screen coordinates for return.
|
||||
rect = [self screenRectFromViewRect:rect];
|
||||
|
||||
if (rect.origin.y >= rect.size.height)
|
||||
rect.origin.y -= rect.size.height;
|
||||
else
|
||||
rect.origin.y = 0;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint {
|
||||
// |thePoint| is in screen coordinates, but needs to be converted to WebKit
|
||||
// coordinates (upper left origin). Scroll offsets will be taken care of in
|
||||
// the renderer.
|
||||
|
||||
CefRect view_rect;
|
||||
renderWidgetHostView_->get_browser_impl()->GetClient()->GetRenderHandler()->
|
||||
GetViewRect(renderWidgetHostView_->get_browser_impl()->GetBrowser(),
|
||||
view_rect);
|
||||
|
||||
thePoint.x -= view_rect.x;
|
||||
thePoint.y -= view_rect.y;
|
||||
thePoint.y = view_rect.height - thePoint.y;
|
||||
|
||||
NSUInteger index = content::TextInputClientMac::GetInstance()->
|
||||
GetCharacterIndexAtPoint(renderWidgetHostView_->GetRenderWidgetHost(),
|
||||
gfx::Point(thePoint.x, thePoint.y));
|
||||
return index;
|
||||
}
|
||||
|
||||
- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent {
|
||||
DCHECK([keyEvent type] == NSKeyDown);
|
||||
// Don't call this method recursively.
|
||||
DCHECK(!handlingKeyDown_);
|
||||
|
||||
oldHasMarkedText_ = hasMarkedText_;
|
||||
handlingKeyDown_ = YES;
|
||||
|
||||
// These variables might be set when handling the keyboard event.
|
||||
// Clear them here so that we can know whether they have changed afterwards.
|
||||
textToBeInserted_.clear();
|
||||
markedText_.clear();
|
||||
underlines_.clear();
|
||||
unmarkTextCalled_ = NO;
|
||||
hasEditCommands_ = NO;
|
||||
editCommands_.clear();
|
||||
}
|
||||
|
||||
- (void)HandleKeyEventAfterTextInputClient:(NSEvent*)keyEvent {
|
||||
handlingKeyDown_ = NO;
|
||||
|
||||
// Then send keypress and/or composition related events.
|
||||
// If there was a marked text or the text to be inserted is longer than 1
|
||||
// character, then we send the text by calling ConfirmComposition().
|
||||
// Otherwise, if the text to be inserted only contains 1 character, then we
|
||||
// can just send a keypress event which is fabricated by changing the type of
|
||||
// the keydown event, so that we can retain all necessary informations, such
|
||||
// as unmodifiedText, etc. And we need to set event.skip_in_browser to true to
|
||||
// prevent the browser from handling it again.
|
||||
// Note that, |textToBeInserted_| is a UTF-16 string, but it's fine to only
|
||||
// handle BMP characters here, as we can always insert non-BMP characters as
|
||||
// text.
|
||||
|
||||
if (!hasMarkedText_ && !oldHasMarkedText_ &&
|
||||
!textToBeInserted_.length() <= 1) {
|
||||
content::NativeWebKeyboardEvent event(keyEvent);
|
||||
if (textToBeInserted_.length() == 1) {
|
||||
event.type = WebKit::WebInputEvent::Type::Char;
|
||||
event.text[0] = textToBeInserted_[0];
|
||||
event.text[1] = 0;
|
||||
}
|
||||
renderWidgetHostView_->SendKeyEvent(event);
|
||||
}
|
||||
|
||||
BOOL textInserted = NO;
|
||||
if (textToBeInserted_.length() >
|
||||
((hasMarkedText_ || oldHasMarkedText_) ? 0u : 1u)) {
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->ImeConfirmComposition(
|
||||
textToBeInserted_);
|
||||
textToBeInserted_ = YES;
|
||||
}
|
||||
|
||||
// Updates or cancels the composition. If some text has been inserted, then
|
||||
// we don't need to cancel the composition explicitly.
|
||||
if (hasMarkedText_ && markedText_.length()) {
|
||||
// Sends the updated marked text to the renderer so it can update the
|
||||
// composition node in WebKit.
|
||||
// When marked text is available, |selectedRange_| will be the range being
|
||||
// selected inside the marked text.
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->ImeSetComposition(
|
||||
markedText_, underlines_, selectedRange_.location,
|
||||
NSMaxRange(selectedRange_));
|
||||
} else if (oldHasMarkedText_ && !hasMarkedText_ && !textInserted) {
|
||||
if (unmarkTextCalled_) {
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->
|
||||
ImeConfirmComposition();
|
||||
} else {
|
||||
renderWidgetHostView_->get_render_widget_host_impl()->
|
||||
ImeCancelComposition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelComposition {
|
||||
if (!hasMarkedText_)
|
||||
return;
|
||||
|
||||
// Cancel the ongoing composition. [NSInputManager markedTextAbandoned:]
|
||||
// doesn't call any NSTextInput functions, such as setMarkedText or
|
||||
// insertText. So, we need to send an IPC message to a renderer so it can
|
||||
// delete the composition node.
|
||||
NSInputManager *currentInputManager = [NSInputManager currentInputManager];
|
||||
[currentInputManager markedTextAbandoned:self];
|
||||
|
||||
hasMarkedText_ = NO;
|
||||
// Should not call [self unmarkText] here, because it'll send unnecessary
|
||||
// cancel composition IPC message to the renderer.
|
||||
}
|
||||
|
||||
@end
|
|
@ -503,6 +503,48 @@ void CEF_CALLBACK browser_host_send_capture_lost_event(
|
|||
CefBrowserHostCppToC::Get(self)->SendCaptureLostEvent();
|
||||
}
|
||||
|
||||
cef_text_input_context_t CEF_CALLBACK browser_host_get_nstext_input_context(
|
||||
struct _cef_browser_host_t* self) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
// Execute
|
||||
cef_text_input_context_t _retval = CefBrowserHostCppToC::Get(
|
||||
self)->GetNSTextInputContext();
|
||||
|
||||
// Return type: simple
|
||||
return _retval;
|
||||
}
|
||||
|
||||
void CEF_CALLBACK browser_host_handle_key_event_before_text_input_client(
|
||||
struct _cef_browser_host_t* self, cef_event_handle_t keyEvent) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
// Execute
|
||||
CefBrowserHostCppToC::Get(self)->HandleKeyEventBeforeTextInputClient(
|
||||
keyEvent);
|
||||
}
|
||||
|
||||
void CEF_CALLBACK browser_host_handle_key_event_after_text_input_client(
|
||||
struct _cef_browser_host_t* self, cef_event_handle_t keyEvent) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
// Execute
|
||||
CefBrowserHostCppToC::Get(self)->HandleKeyEventAfterTextInputClient(
|
||||
keyEvent);
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR - Do not edit by hand.
|
||||
|
||||
|
@ -540,6 +582,12 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls)
|
|||
struct_.struct_.send_focus_event = browser_host_send_focus_event;
|
||||
struct_.struct_.send_capture_lost_event =
|
||||
browser_host_send_capture_lost_event;
|
||||
struct_.struct_.get_nstext_input_context =
|
||||
browser_host_get_nstext_input_context;
|
||||
struct_.struct_.handle_key_event_before_text_input_client =
|
||||
browser_host_handle_key_event_before_text_input_client;
|
||||
struct_.struct_.handle_key_event_after_text_input_client =
|
||||
browser_host_handle_key_event_after_text_input_client;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
|
|
@ -387,6 +387,43 @@ void CefBrowserHostCToCpp::SendCaptureLostEvent() {
|
|||
struct_->send_capture_lost_event(struct_);
|
||||
}
|
||||
|
||||
CefTextInputContext CefBrowserHostCToCpp::GetNSTextInputContext() {
|
||||
if (CEF_MEMBER_MISSING(struct_, get_nstext_input_context))
|
||||
return NULL;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Execute
|
||||
cef_text_input_context_t _retval = struct_->get_nstext_input_context(struct_);
|
||||
|
||||
// Return type: simple
|
||||
return _retval;
|
||||
}
|
||||
|
||||
void CefBrowserHostCToCpp::HandleKeyEventBeforeTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
if (CEF_MEMBER_MISSING(struct_, handle_key_event_before_text_input_client))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Execute
|
||||
struct_->handle_key_event_before_text_input_client(struct_,
|
||||
keyEvent);
|
||||
}
|
||||
|
||||
void CefBrowserHostCToCpp::HandleKeyEventAfterTextInputClient(
|
||||
CefEventHandle keyEvent) {
|
||||
if (CEF_MEMBER_MISSING(struct_, handle_key_event_after_text_input_client))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Execute
|
||||
struct_->handle_key_event_after_text_input_client(struct_,
|
||||
keyEvent);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<> long CefCToCpp<CefBrowserHostCToCpp, CefBrowserHost,
|
||||
|
|
|
@ -69,6 +69,11 @@ class CefBrowserHostCToCpp
|
|||
int deltaY) OVERRIDE;
|
||||
virtual void SendFocusEvent(bool setFocus) OVERRIDE;
|
||||
virtual void SendCaptureLostEvent() OVERRIDE;
|
||||
virtual CefTextInputContext GetNSTextInputContext() OVERRIDE;
|
||||
virtual void HandleKeyEventBeforeTextInputClient(
|
||||
CefEventHandle keyEvent) OVERRIDE;
|
||||
virtual void HandleKeyEventAfterTextInputClient(
|
||||
CefEventHandle keyEvent) OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // USING_CEF_SHARED
|
||||
|
|
|
@ -308,7 +308,9 @@ void ClientOSRHandler::SetLoading(bool isLoading) {
|
|||
}
|
||||
|
||||
- (CefRefPtr<CefBrowser>)getBrowser {
|
||||
return browser_provider_->GetBrowser();
|
||||
if (browser_provider_)
|
||||
return browser_provider_->GetBrowser();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- (void)setFrame:(NSRect)frameRect {
|
||||
|
@ -434,41 +436,16 @@ void ClientOSRHandler::SetLoading(bool isLoading) {
|
|||
if (!browser)
|
||||
return;
|
||||
|
||||
CefKeyEvent keyEvent;
|
||||
[self getKeyEvent:keyEvent forEvent:event];
|
||||
if ([event type] != NSFlagsChanged) {
|
||||
browser->GetHost()->HandleKeyEventBeforeTextInputClient(event);
|
||||
|
||||
keyEvent.type = KEYEVENT_KEYDOWN;
|
||||
browser->GetHost()->SendKeyEvent(keyEvent);
|
||||
// The return value of this method seems to always be set to YES,
|
||||
// thus we ignore it and ask the host view whether IME is active
|
||||
// or not.
|
||||
[[self inputContext] handleEvent:event];
|
||||
|
||||
if ([event modifierFlags] & (NSNumericPadKeyMask | NSFunctionKeyMask)) {
|
||||
// Don't send a Char event for non-char keys like arrows, function keys and
|
||||
// clear.
|
||||
switch (keyEvent.native_key_code) {
|
||||
case 81: // =
|
||||
case 75: // /
|
||||
case 67: // *
|
||||
case 78: // -
|
||||
case 69: // +
|
||||
case 76: // Enter
|
||||
case 65: // .
|
||||
case 82: // 0
|
||||
case 83: // 1
|
||||
case 84: // 2
|
||||
case 85: // 3
|
||||
case 86: // 4
|
||||
case 87: // 5
|
||||
case 88: // 6
|
||||
case 89: // 7
|
||||
case 91: // 8
|
||||
case 92: // 9
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
browser->GetHost()->HandleKeyEventAfterTextInputClient(event);
|
||||
}
|
||||
|
||||
keyEvent.type = KEYEVENT_CHAR;
|
||||
browser->GetHost()->SendKeyEvent(keyEvent);
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event {
|
||||
|
@ -611,6 +588,13 @@ void ClientOSRHandler::SetLoading(bool isLoading) {
|
|||
keyEvent.modifiers = [self getModifiersForEvent:event];
|
||||
}
|
||||
|
||||
- (NSTextInputContext*)inputContext {
|
||||
CefRefPtr<CefBrowser> browser = [self getBrowser];
|
||||
if (browser)
|
||||
return browser->GetHost()->GetNSTextInputContext();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event {
|
||||
NSPoint point = [self getClickPointForEvent:event];
|
||||
mouseEvent.x = point.x;
|
||||
|
|
|
@ -376,6 +376,7 @@ _simpletypes = {
|
|||
'CefCursorHandle' : ['cef_cursor_handle_t', 'NULL'],
|
||||
'CefEventHandle' : ['cef_event_handle_t', 'NULL'],
|
||||
'CefWindowHandle' : ['cef_window_handle_t', 'NULL'],
|
||||
'CefTextInputContext' : ['cef_text_input_context_t' ,'NULL'],
|
||||
'CefRect' : ['cef_rect_t', 'CefRect()'],
|
||||
'CefThreadId' : ['cef_thread_id_t', 'TID_UI'],
|
||||
'CefTime' : ['cef_time_t', 'CefTime()'],
|
||||
|
|
Loading…
Reference in New Issue