This source file includes following definitions.
- ShouldForgetPreviousClick
- ResetClickCountState
- IsKeyPadKeyval
- GdkEventTimeToWebEventTime
- GdkStateToWebEventModifiers
- GdkEventToWindowsKeyCode
- NormalizeEventState
- GetControlCharacter
- ScrollbarPixelsPerTick
#include "content/browser/renderer_host/input/web_input_event_builders_gtk.h"
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include "base/logging.h"
#include "content/browser/renderer_host/input/web_input_event_util_posix.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/keycodes/keyboard_code_conversion_gtk.h"
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebKeyboardEvent;
namespace {
static int num_clicks = 0;
static GdkWindow* last_click_event_window = 0;
static gint last_click_time = 0;
static gint last_click_x = 0;
static gint last_click_y = 0;
static WebMouseEvent::Button last_click_button = WebMouseEvent::ButtonNone;
bool ShouldForgetPreviousClick(GdkWindow* window, gint time, gint x, gint y) {
static GtkSettings* settings = gtk_settings_get_default();
if (window != last_click_event_window)
return true;
gint double_click_time = 250;
gint double_click_distance = 5;
g_object_get(G_OBJECT(settings),
"gtk-double-click-time",
&double_click_time,
"gtk-double-click-distance",
&double_click_distance,
NULL);
return (time - last_click_time) > double_click_time ||
std::abs(x - last_click_x) > double_click_distance ||
std::abs(y - last_click_y) > double_click_distance;
}
void ResetClickCountState() {
num_clicks = 0;
last_click_event_window = 0;
last_click_time = 0;
last_click_x = 0;
last_click_y = 0;
last_click_button = blink::WebMouseEvent::ButtonNone;
}
bool IsKeyPadKeyval(guint keyval) {
return keyval >= GDK_KP_Space && keyval <= GDK_KP_9;
}
double GdkEventTimeToWebEventTime(guint32 time) {
return time / 1000.0;
}
int GdkStateToWebEventModifiers(guint state) {
int modifiers = 0;
if (state & GDK_SHIFT_MASK)
modifiers |= WebInputEvent::ShiftKey;
if (state & GDK_CONTROL_MASK)
modifiers |= WebInputEvent::ControlKey;
if (state & GDK_MOD1_MASK)
modifiers |= WebInputEvent::AltKey;
if (state & GDK_META_MASK)
modifiers |= WebInputEvent::MetaKey;
if (state & GDK_BUTTON1_MASK)
modifiers |= WebInputEvent::LeftButtonDown;
if (state & GDK_BUTTON2_MASK)
modifiers |= WebInputEvent::MiddleButtonDown;
if (state & GDK_BUTTON3_MASK)
modifiers |= WebInputEvent::RightButtonDown;
if (state & GDK_LOCK_MASK)
modifiers |= WebInputEvent::CapsLockOn;
if (state & GDK_MOD2_MASK)
modifiers |= WebInputEvent::NumLockOn;
return modifiers;
}
ui::KeyboardCode GdkEventToWindowsKeyCode(const GdkEventKey* event) {
static const unsigned int kHardwareCodeToGDKKeyval[] = {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
GDK_1,
GDK_2,
GDK_3,
GDK_4,
GDK_5,
GDK_6,
GDK_7,
GDK_8,
GDK_9,
GDK_0,
GDK_minus,
GDK_equal,
0,
0,
GDK_q,
GDK_w,
GDK_e,
GDK_r,
GDK_t,
GDK_y,
GDK_u,
GDK_i,
GDK_o,
GDK_p,
GDK_bracketleft,
GDK_bracketright,
0,
0,
GDK_a,
GDK_s,
GDK_d,
GDK_f,
GDK_g,
GDK_h,
GDK_j,
GDK_k,
GDK_l,
GDK_semicolon,
GDK_apostrophe,
GDK_grave,
0,
GDK_backslash,
GDK_z,
GDK_x,
GDK_c,
GDK_v,
GDK_b,
GDK_n,
GDK_m,
GDK_comma,
GDK_period,
GDK_slash,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
GDK_Super_L,
GDK_Super_R,
};
ui::KeyboardCode windows_key_code =
ui::WindowsKeyCodeForGdkKeyCode(event->keyval);
if (windows_key_code)
return windows_key_code;
if (event->hardware_keycode < arraysize(kHardwareCodeToGDKKeyval)) {
int keyval = kHardwareCodeToGDKKeyval[event->hardware_keycode];
if (keyval)
return ui::WindowsKeyCodeForGdkKeyCode(keyval);
}
return ui::WindowsKeyCodeForGdkKeyCode(event->keyval);
}
guint NormalizeEventState(const GdkEventKey* event) {
guint mask = 0;
switch (GdkEventToWindowsKeyCode(event)) {
case ui::VKEY_CONTROL:
case ui::VKEY_LCONTROL:
case ui::VKEY_RCONTROL:
mask = GDK_CONTROL_MASK;
break;
case ui::VKEY_SHIFT:
case ui::VKEY_LSHIFT:
case ui::VKEY_RSHIFT:
mask = GDK_SHIFT_MASK;
break;
case ui::VKEY_MENU:
case ui::VKEY_LMENU:
case ui::VKEY_RMENU:
mask = GDK_MOD1_MASK;
break;
case ui::VKEY_CAPITAL:
mask = GDK_LOCK_MASK;
break;
default:
return event->state;
}
if (event->type == GDK_KEY_PRESS)
return event->state | mask;
return event->state & ~mask;
}
int GetControlCharacter(ui::KeyboardCode windows_key_code, bool shift) {
if (windows_key_code >= ui::VKEY_A && windows_key_code <= ui::VKEY_Z) {
return windows_key_code - ui::VKEY_A + 1;
}
if (shift) {
switch (windows_key_code) {
case ui::VKEY_2:
return 0;
case ui::VKEY_6:
return 0x1E;
case ui::VKEY_OEM_MINUS:
return 0x1F;
default:
return 0;
}
} else {
switch (windows_key_code) {
case ui::VKEY_OEM_4:
return 0x1B;
case ui::VKEY_OEM_5:
return 0x1C;
case ui::VKEY_OEM_6:
return 0x1D;
case ui::VKEY_RETURN:
return 0x0A;
default:
return 0;
}
}
}
}
namespace content {
WebKeyboardEvent WebKeyboardEventBuilder::Build(const GdkEventKey* event) {
WebKeyboardEvent result;
result.timeStampSeconds = GdkEventTimeToWebEventTime(event->time);
result.modifiers = GdkStateToWebEventModifiers(NormalizeEventState(event));
switch (event->type) {
case GDK_KEY_RELEASE:
result.type = WebInputEvent::KeyUp;
break;
case GDK_KEY_PRESS:
result.type = WebInputEvent::RawKeyDown;
break;
default:
NOTREACHED();
}
if (result.modifiers & WebInputEvent::AltKey)
result.isSystemKey = true;
ui::KeyboardCode windows_key_code = GdkEventToWindowsKeyCode(event);
result.windowsKeyCode = GetWindowsKeyCodeWithoutLocation(windows_key_code);
result.modifiers |= GetLocationModifiersFromWindowsKeyCode(windows_key_code);
result.nativeKeyCode = event->hardware_keycode;
if (result.windowsKeyCode == ui::VKEY_RETURN) {
result.unmodifiedText[0] = '\r';
} else {
result.unmodifiedText[0] =
static_cast<int>(gdk_keyval_to_unicode(event->keyval));
}
if (result.modifiers & WebInputEvent::ControlKey) {
result.text[0] =
GetControlCharacter(ui::KeyboardCode(result.windowsKeyCode),
result.modifiers & WebInputEvent::ShiftKey);
} else {
result.text[0] = result.unmodifiedText[0];
}
result.setKeyIdentifierFromWindowsKeyCode();
if (IsKeyPadKeyval(event->keyval))
result.modifiers |= WebInputEvent::IsKeyPad;
return result;
}
WebKeyboardEvent WebKeyboardEventBuilder::Build(wchar_t character,
int state,
double timeStampSeconds) {
WebKeyboardEvent result;
result.type = blink::WebInputEvent::Char;
result.timeStampSeconds = timeStampSeconds;
result.modifiers = GdkStateToWebEventModifiers(state);
result.windowsKeyCode = character;
result.nativeKeyCode = character;
result.text[0] = character;
result.unmodifiedText[0] = character;
if (result.modifiers & WebInputEvent::AltKey)
result.isSystemKey = true;
return result;
}
WebMouseEvent WebMouseEventBuilder::Build(const GdkEventButton* event) {
WebMouseEvent result;
result.timeStampSeconds = GdkEventTimeToWebEventTime(event->time);
result.modifiers = GdkStateToWebEventModifiers(event->state);
result.x = static_cast<int>(event->x);
result.y = static_cast<int>(event->y);
result.windowX = result.x;
result.windowY = result.y;
result.globalX = static_cast<int>(event->x_root);
result.globalY = static_cast<int>(event->y_root);
result.clickCount = 0;
switch (event->type) {
case GDK_BUTTON_PRESS:
result.type = WebInputEvent::MouseDown;
break;
case GDK_BUTTON_RELEASE:
result.type = WebInputEvent::MouseUp;
break;
case GDK_3BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
default:
NOTREACHED();
}
result.button = WebMouseEvent::ButtonNone;
if (event->button == 1)
result.button = WebMouseEvent::ButtonLeft;
else if (event->button == 2)
result.button = WebMouseEvent::ButtonMiddle;
else if (event->button == 3)
result.button = WebMouseEvent::ButtonRight;
if (result.type == WebInputEvent::MouseDown) {
bool forgetPreviousClick = ShouldForgetPreviousClick(
event->window, event->time, event->x, event->y);
if (!forgetPreviousClick && result.button == last_click_button) {
++num_clicks;
} else {
num_clicks = 1;
last_click_event_window = event->window;
last_click_x = event->x;
last_click_y = event->y;
last_click_button = result.button;
}
last_click_time = event->time;
}
result.clickCount = num_clicks;
return result;
}
WebMouseEvent WebMouseEventBuilder::Build(const GdkEventMotion* event) {
WebMouseEvent result;
result.timeStampSeconds = GdkEventTimeToWebEventTime(event->time);
result.modifiers = GdkStateToWebEventModifiers(event->state);
result.x = static_cast<int>(event->x);
result.y = static_cast<int>(event->y);
result.windowX = result.x;
result.windowY = result.y;
result.globalX = static_cast<int>(event->x_root);
result.globalY = static_cast<int>(event->y_root);
switch (event->type) {
case GDK_MOTION_NOTIFY:
result.type = WebInputEvent::MouseMove;
break;
default:
NOTREACHED();
}
result.button = WebMouseEvent::ButtonNone;
if (event->state & GDK_BUTTON1_MASK)
result.button = WebMouseEvent::ButtonLeft;
else if (event->state & GDK_BUTTON2_MASK)
result.button = WebMouseEvent::ButtonMiddle;
else if (event->state & GDK_BUTTON3_MASK)
result.button = WebMouseEvent::ButtonRight;
if (ShouldForgetPreviousClick(event->window, event->time, event->x, event->y))
ResetClickCountState();
return result;
}
WebMouseEvent WebMouseEventBuilder::Build(const GdkEventCrossing* event) {
WebMouseEvent result;
result.timeStampSeconds = GdkEventTimeToWebEventTime(event->time);
result.modifiers = GdkStateToWebEventModifiers(event->state);
result.x = static_cast<int>(event->x);
result.y = static_cast<int>(event->y);
result.windowX = result.x;
result.windowY = result.y;
result.globalX = static_cast<int>(event->x_root);
result.globalY = static_cast<int>(event->y_root);
switch (event->type) {
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
result.type = WebInputEvent::MouseMove;
break;
default:
NOTREACHED();
}
result.button = WebMouseEvent::ButtonNone;
if (event->state & GDK_BUTTON1_MASK)
result.button = WebMouseEvent::ButtonLeft;
else if (event->state & GDK_BUTTON2_MASK)
result.button = WebMouseEvent::ButtonMiddle;
else if (event->state & GDK_BUTTON3_MASK)
result.button = WebMouseEvent::ButtonRight;
if (ShouldForgetPreviousClick(event->window, event->time, event->x, event->y))
ResetClickCountState();
return result;
}
float WebMouseWheelEventBuilder::ScrollbarPixelsPerTick() {
return 160.0f / 3.0f;
}
WebMouseWheelEvent WebMouseWheelEventBuilder::Build(
const GdkEventScroll* event) {
WebMouseWheelEvent result;
result.type = WebInputEvent::MouseWheel;
result.button = WebMouseEvent::ButtonNone;
result.timeStampSeconds = GdkEventTimeToWebEventTime(event->time);
result.modifiers = GdkStateToWebEventModifiers(event->state);
result.x = static_cast<int>(event->x);
result.y = static_cast<int>(event->y);
result.windowX = result.x;
result.windowY = result.y;
result.globalX = static_cast<int>(event->x_root);
result.globalY = static_cast<int>(event->y_root);
static const float scrollbarPixelsPerTick = ScrollbarPixelsPerTick();
switch (event->direction) {
case GDK_SCROLL_UP:
result.deltaY = scrollbarPixelsPerTick;
result.wheelTicksY = 1;
break;
case GDK_SCROLL_DOWN:
result.deltaY = -scrollbarPixelsPerTick;
result.wheelTicksY = -1;
break;
case GDK_SCROLL_LEFT:
result.deltaX = scrollbarPixelsPerTick;
result.wheelTicksX = 1;
break;
case GDK_SCROLL_RIGHT:
result.deltaX = -scrollbarPixelsPerTick;
result.wheelTicksX = -1;
break;
}
return result;
}
}