Merge pull request #2369 from atom/better-modifiers
Fix a few things of Tray
This commit is contained in:
commit
d5893d8c9f
9 changed files with 129 additions and 34 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||||
#include "native_mate/constructor.h"
|
#include "native_mate/constructor.h"
|
||||||
#include "native_mate/dictionary.h"
|
#include "native_mate/dictionary.h"
|
||||||
|
#include "ui/events/event_constants.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
@ -41,11 +42,24 @@ mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
|
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
|
||||||
Emit("clicked", bounds, modifiers);
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
EmitCustomEvent("clicked",
|
||||||
|
ModifiersToObject(isolate(), modifiers), bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
||||||
Emit("double-clicked", bounds, modifiers);
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
EmitCustomEvent("double-clicked",
|
||||||
|
ModifiersToObject(isolate(), modifiers), bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
|
||||||
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
EmitCustomEvent("right-clicked",
|
||||||
|
ModifiersToObject(isolate(), modifiers), bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tray::OnBalloonShow() {
|
void Tray::OnBalloonShow() {
|
||||||
|
@ -60,10 +74,6 @@ void Tray::OnBalloonClosed() {
|
||||||
Emit("balloon-closed");
|
Emit("balloon-closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
|
|
||||||
Emit("right-clicked", bounds, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tray::OnDropFiles(const std::vector<std::string>& files) {
|
void Tray::OnDropFiles(const std::vector<std::string>& files) {
|
||||||
Emit("drop-files", files);
|
Emit("drop-files", files);
|
||||||
}
|
}
|
||||||
|
@ -120,6 +130,16 @@ void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
|
||||||
tray_icon_->SetContextMenu(menu->model());
|
tray_icon_->SetContextMenu(menu->model());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
|
||||||
|
int modifiers) {
|
||||||
|
mate::Dictionary obj(isolate, v8::Object::New(isolate));
|
||||||
|
obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
|
||||||
|
obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
|
||||||
|
obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
|
||||||
|
obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
|
||||||
|
return obj.GetHandle();
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Tray::BuildPrototype(v8::Isolate* isolate,
|
void Tray::BuildPrototype(v8::Isolate* isolate,
|
||||||
v8::Local<v8::ObjectTemplate> prototype) {
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
|
|
@ -44,10 +44,10 @@ class Tray : public mate::EventEmitter,
|
||||||
// TrayIconObserver:
|
// TrayIconObserver:
|
||||||
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||||
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
|
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||||
|
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||||
void OnBalloonShow() override;
|
void OnBalloonShow() override;
|
||||||
void OnBalloonClicked() override;
|
void OnBalloonClicked() override;
|
||||||
void OnBalloonClosed() override;
|
void OnBalloonClosed() override;
|
||||||
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
|
||||||
void OnDropFiles(const std::vector<std::string>& files) override;
|
void OnDropFiles(const std::vector<std::string>& files) override;
|
||||||
|
|
||||||
// mate::Wrappable:
|
// mate::Wrappable:
|
||||||
|
@ -64,6 +64,8 @@ class Tray : public mate::EventEmitter,
|
||||||
void SetContextMenu(mate::Arguments* args, Menu* menu);
|
void SetContextMenu(mate::Arguments* args, Menu* menu);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
|
||||||
|
|
||||||
scoped_ptr<TrayIcon> tray_icon_;
|
scoped_ptr<TrayIcon> tray_icon_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Tray);
|
DISALLOW_COPY_AND_ASSIGN(Tray);
|
||||||
|
|
|
@ -37,9 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
|
||||||
EventEmitter::EventEmitter() {
|
EventEmitter::EventEmitter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
|
v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
||||||
content::WebContents* sender,
|
v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
|
||||||
IPC::Message* message) {
|
|
||||||
v8::Local<v8::Object> event;
|
v8::Local<v8::Object> event;
|
||||||
bool use_native_event = sender && message;
|
bool use_native_event = sender && message;
|
||||||
|
|
||||||
|
@ -54,4 +53,12 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
||||||
|
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
||||||
|
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
||||||
|
event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||||
|
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
|
@ -25,6 +25,14 @@ class EventEmitter : public Wrappable {
|
||||||
public:
|
public:
|
||||||
typedef std::vector<v8::Local<v8::Value>> ValueArray;
|
typedef std::vector<v8::Local<v8::Value>> ValueArray;
|
||||||
|
|
||||||
|
// this.emit(name, event, args...);
|
||||||
|
template<typename... Args>
|
||||||
|
bool EmitCustomEvent(const base::StringPiece& name,
|
||||||
|
v8::Local<v8::Object> event,
|
||||||
|
const Args&... args) {
|
||||||
|
return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...);
|
||||||
|
}
|
||||||
|
|
||||||
// this.emit(name, new Event(), args...);
|
// this.emit(name, new Event(), args...);
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
bool Emit(const base::StringPiece& name, const Args&... args) {
|
bool Emit(const base::StringPiece& name, const Args&... args) {
|
||||||
|
@ -37,21 +45,31 @@ class EventEmitter : public Wrappable {
|
||||||
content::WebContents* sender,
|
content::WebContents* sender,
|
||||||
IPC::Message* message,
|
IPC::Message* message,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
v8::Locker locker(isolate());
|
|
||||||
v8::HandleScope handle_scope(isolate());
|
|
||||||
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
||||||
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
|
return EmitWithEvent(name, event, args...);
|
||||||
return event->Get(
|
|
||||||
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EventEmitter();
|
EventEmitter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// this.emit(name, event, args...);
|
||||||
|
template<typename... Args>
|
||||||
|
bool EmitWithEvent(const base::StringPiece& name,
|
||||||
|
v8::Local<v8::Object> event,
|
||||||
|
const Args&... args) {
|
||||||
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
|
||||||
|
return event->Get(
|
||||||
|
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
|
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
|
||||||
content::WebContents* sender,
|
content::WebContents* sender,
|
||||||
IPC::Message* message);
|
IPC::Message* message);
|
||||||
|
v8::Local<v8::Object> CreateCustomEvent(
|
||||||
|
v8::Isolate* isolate, v8::Local<v8::Object> event);
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
|
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,23 +63,32 @@ NotifyIcon::~NotifyIcon() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
|
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
|
||||||
bool left_mouse_click) {
|
int modifiers,
|
||||||
|
bool left_mouse_click,
|
||||||
|
bool double_button_click) {
|
||||||
NOTIFYICONIDENTIFIER icon_id;
|
NOTIFYICONIDENTIFIER icon_id;
|
||||||
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
|
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
|
||||||
icon_id.uID = icon_id_;
|
icon_id.uID = icon_id_;
|
||||||
icon_id.hWnd = window_;
|
icon_id.hWnd = window_;
|
||||||
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
|
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
|
||||||
|
if (has_tray_app_id_hash_)
|
||||||
|
memcpy(reinterpret_cast<void*>(&icon_id.guidItem),
|
||||||
|
&tray_app_id_hash_,
|
||||||
|
sizeof(GUID));
|
||||||
|
|
||||||
RECT rect = { 0 };
|
RECT rect = { 0 };
|
||||||
Shell_NotifyIconGetRect(&icon_id, &rect);
|
Shell_NotifyIconGetRect(&icon_id, &rect);
|
||||||
|
|
||||||
// Pass to the observer if appropriate.
|
|
||||||
if (left_mouse_click) {
|
if (left_mouse_click) {
|
||||||
NotifyClicked(gfx::Rect(rect));
|
if (double_button_click) // double left click
|
||||||
|
NotifyDoubleClicked(gfx::Rect(rect), modifiers);
|
||||||
|
else // single left click
|
||||||
|
NotifyClicked(gfx::Rect(rect), modifiers);
|
||||||
return;
|
return;
|
||||||
}
|
} else if (!double_button_click) { // single right click
|
||||||
|
NotifyRightClicked(gfx::Rect(rect), modifiers);
|
||||||
NotifyRightClicked(gfx::Rect(rect));
|
|
||||||
PopContextMenu(cursor_pos);
|
PopContextMenu(cursor_pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyIcon::ResetIcon() {
|
void NotifyIcon::ResetIcon() {
|
||||||
|
|
|
@ -33,7 +33,10 @@ class NotifyIcon : public TrayIcon {
|
||||||
// Handles a click event from the user - if |left_button_click| is true and
|
// Handles a click event from the user - if |left_button_click| is true and
|
||||||
// there is a registered observer, passes the click event to the observer,
|
// there is a registered observer, passes the click event to the observer,
|
||||||
// otherwise displays the context menu if there is one.
|
// otherwise displays the context menu if there is one.
|
||||||
void HandleClickEvent(const gfx::Point& cursor_pos, bool left_button_click);
|
void HandleClickEvent(const gfx::Point& cursor_pos,
|
||||||
|
int modifiers,
|
||||||
|
bool left_button_click,
|
||||||
|
bool double_button_click);
|
||||||
|
|
||||||
// Re-creates the status tray icon now after the taskbar has been created.
|
// Re-creates the status tray icon now after the taskbar has been created.
|
||||||
void ResetIcon();
|
void ResetIcon();
|
||||||
|
|
|
@ -5,13 +5,16 @@
|
||||||
#include "atom/browser/ui/win/notify_icon_host.h"
|
#include "atom/browser/ui/win/notify_icon_host.h"
|
||||||
|
|
||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
|
#include <winuser.h>
|
||||||
|
|
||||||
#include "atom/browser/ui/win/notify_icon.h"
|
#include "atom/browser/ui/win/notify_icon.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/stl_util.h"
|
#include "base/stl_util.h"
|
||||||
#include "base/threading/non_thread_safe.h"
|
#include "base/threading/non_thread_safe.h"
|
||||||
#include "base/threading/thread.h"
|
#include "base/threading/thread.h"
|
||||||
|
#include "base/win/win_util.h"
|
||||||
#include "base/win/wrapped_window_proc.h"
|
#include "base/win/wrapped_window_proc.h"
|
||||||
|
#include "ui/events/event_constants.h"
|
||||||
#include "ui/gfx/screen.h"
|
#include "ui/gfx/screen.h"
|
||||||
#include "ui/gfx/win/hwnd_util.h"
|
#include "ui/gfx/win/hwnd_util.h"
|
||||||
|
|
||||||
|
@ -26,6 +29,24 @@ const UINT kBaseIconId = 2;
|
||||||
|
|
||||||
const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow";
|
const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow";
|
||||||
|
|
||||||
|
bool IsWinPressed() {
|
||||||
|
return ((::GetKeyState(VK_LWIN) & 0x8000) == 0x8000) ||
|
||||||
|
((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetKeyboardModifers() {
|
||||||
|
int modifiers = ui::EF_NONE;
|
||||||
|
if (base::win::IsShiftPressed())
|
||||||
|
modifiers |= ui::EF_SHIFT_DOWN;
|
||||||
|
if (base::win::IsCtrlPressed())
|
||||||
|
modifiers |= ui::EF_CONTROL_DOWN;
|
||||||
|
if (base::win::IsAltPressed())
|
||||||
|
modifiers |= ui::EF_ALT_DOWN;
|
||||||
|
if (IsWinPressed())
|
||||||
|
modifiers |= ui::EF_COMMAND_DOWN;
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
NotifyIconHost::NotifyIconHost()
|
NotifyIconHost::NotifyIconHost()
|
||||||
|
@ -146,12 +167,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
|
||||||
|
|
||||||
case WM_LBUTTONDOWN:
|
case WM_LBUTTONDOWN:
|
||||||
case WM_RBUTTONDOWN:
|
case WM_RBUTTONDOWN:
|
||||||
|
case WM_LBUTTONDBLCLK:
|
||||||
|
case WM_RBUTTONDBLCLK:
|
||||||
case WM_CONTEXTMENU:
|
case WM_CONTEXTMENU:
|
||||||
// Walk our icons, find which one was clicked on, and invoke its
|
// Walk our icons, find which one was clicked on, and invoke its
|
||||||
// HandleClickEvent() method.
|
// HandleClickEvent() method.
|
||||||
gfx::Point cursor_pos(
|
gfx::Point cursor_pos(
|
||||||
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
|
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
|
||||||
win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
|
win_icon->HandleClickEvent(
|
||||||
|
cursor_pos,
|
||||||
|
GetKeyboardModifers(),
|
||||||
|
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
|
||||||
|
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,7 @@ void NativeImage::SetTemplateImage(bool setAsTemplate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NativeImage::IsTemplateImage() {
|
bool NativeImage::IsTemplateImage() {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,16 @@ Creates a new tray icon associated with the `image`.
|
||||||
|
|
||||||
### Event: 'clicked'
|
### Event: 'clicked'
|
||||||
|
|
||||||
* `event`
|
* `event` Event
|
||||||
|
* `altKey` Boolean
|
||||||
|
* `shiftKey` Boolean
|
||||||
|
* `ctrlKey` Boolean
|
||||||
|
* `metaKey` Boolean
|
||||||
* `bounds` Object - the bounds of tray icon
|
* `bounds` Object - the bounds of tray icon
|
||||||
* `x` Integer
|
* `x` Integer
|
||||||
* `y` Integer
|
* `y` Integer
|
||||||
* `width` Integer
|
* `width` Integer
|
||||||
* `height` Integer
|
* `height` Integer
|
||||||
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
|
|
||||||
|
|
||||||
Emitted when the tray icon is clicked.
|
Emitted when the tray icon is clicked.
|
||||||
|
|
||||||
|
@ -61,32 +64,37 @@ __Note:__ The `bounds` payload is only implemented on OS X and Windows 7 or newe
|
||||||
|
|
||||||
### Event: 'right-clicked'
|
### Event: 'right-clicked'
|
||||||
|
|
||||||
* `event`
|
* `event` Event
|
||||||
|
* `altKey` Boolean
|
||||||
|
* `shiftKey` Boolean
|
||||||
|
* `ctrlKey` Boolean
|
||||||
|
* `metaKey` Boolean
|
||||||
* `bounds` Object - the bounds of tray icon
|
* `bounds` Object - the bounds of tray icon
|
||||||
* `x` Integer
|
* `x` Integer
|
||||||
* `y` Integer
|
* `y` Integer
|
||||||
* `width` Integer
|
* `width` Integer
|
||||||
* `height` Integer
|
* `height` Integer
|
||||||
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
|
|
||||||
|
|
||||||
Emitted when the tray icon is right clicked.
|
Emitted when the tray icon is right clicked.
|
||||||
|
|
||||||
__Note:__ This is only implemented on OS X and Windows. On Windows, this event
|
__Note:__ This is only implemented on OS X and Windows.
|
||||||
will be emitted if the tray icon has context menu.
|
|
||||||
|
|
||||||
### Event: 'double-clicked'
|
### Event: 'double-clicked'
|
||||||
|
|
||||||
* `event`
|
* `event` Event
|
||||||
|
* `altKey` Boolean
|
||||||
|
* `shiftKey` Boolean
|
||||||
|
* `ctrlKey` Boolean
|
||||||
|
* `metaKey` Boolean
|
||||||
* `bounds` Object - the bounds of tray icon
|
* `bounds` Object - the bounds of tray icon
|
||||||
* `x` Integer
|
* `x` Integer
|
||||||
* `y` Integer
|
* `y` Integer
|
||||||
* `width` Integer
|
* `width` Integer
|
||||||
* `height` Integer
|
* `height` Integer
|
||||||
* [`modifiers`][modifiers] Integer - bitsum of keyboard modifiers and mouse keys
|
|
||||||
|
|
||||||
Emitted when the tray icon is double clicked.
|
Emitted when the tray icon is double clicked.
|
||||||
|
|
||||||
__Note:__ This is only implemented on OS X.
|
__Note:__ This is only implemented on OS X and Windows.
|
||||||
|
|
||||||
### Event: 'balloon-show'
|
### Event: 'balloon-show'
|
||||||
|
|
||||||
|
@ -171,9 +179,10 @@ __Note:__ This is only implemented on Windows.
|
||||||
* `x` Integer
|
* `x` Integer
|
||||||
* `y` Integer
|
* `y` Integer
|
||||||
|
|
||||||
__Note:__ This is only implemented on OS X and Windows.
|
|
||||||
The `position` is only available on Windows, and it is (0, 0) by default.
|
The `position` is only available on Windows, and it is (0, 0) by default.
|
||||||
|
|
||||||
|
__Note:__ This is only implemented on OS X and Windows.
|
||||||
|
|
||||||
### Tray.setContextMenu(menu)
|
### Tray.setContextMenu(menu)
|
||||||
|
|
||||||
* `menu` Menu
|
* `menu` Menu
|
||||||
|
@ -181,4 +190,3 @@ The `position` is only available on Windows, and it is (0, 0) by default.
|
||||||
Sets the context menu for this icon.
|
Sets the context menu for this icon.
|
||||||
|
|
||||||
[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter
|
[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter
|
||||||
[modifiers]: https://code.google.com/p/chromium/codesearch#chromium/src/ui/events/event_constants.h&l=77
|
|
||||||
|
|
Loading…
Reference in a new issue