Bug 1338369 part.2 nsWindow for GTK should consume Shift key state of eContextMenu event if it's caused by Shift+F10 r=karlt,smaug

Shift+F10 is also well-known shortcut key on Linux.  So, it should behave same as pressing ContextMenu key.  So, for allowing web page to prevent its default, nsWindow for GTK needs to consume Shift key state at dispatching eContextMenu key.

Additionally, we should allow to open context menu with Shift+ContextMenu because only ContextMenu key press can be prevented its default by web page.  Therefore, we should allow users to open context menu even with keyboard even if web content doesn't want it.

Note that Ctrl+Shift+F10 or Alt+Shift+F10 should behave same as Shift+ContextMenu key, but we should discuss later.

MozReview-Commit-ID: 1mPGKMTsrkv

--HG--
extra : rebase_source : 75dd8333b24f5e2f4ded4414b5e5ee85de253cc7
This commit is contained in:
Masayuki Nakano 2017-03-09 18:53:24 +09:00
Родитель 9021b5582c
Коммит fee81e4718
3 изменённых файлов: 86 добавлений и 44 удалений

Просмотреть файл

@ -39,7 +39,7 @@ public:
/**
* Compute a DOM key name index from aGdkKeyEvent.
*/
KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent);
static KeyNameIndex ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent);
/**
* Compute a DOM code name index from aGdkKeyEvent.

Просмотреть файл

@ -167,8 +167,6 @@ static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
gint x, gint y,
gint *retx, gint *rety);
static inline bool is_context_menu_key(const WidgetKeyboardEvent& inKeyEvent);
static int is_parent_ungrab_enter(GdkEventCrossing *aEvent);
static int is_parent_grab_leave(GdkEventCrossing *aEvent);
@ -3065,43 +3063,85 @@ nsWindow::OnKeyPressEvent(GdkEventKey *aEvent)
// before we dispatch a key, check if it's the context menu key.
// If so, send a context menu key event instead.
if (is_context_menu_key(keypressEvent)) {
WidgetMouseEvent contextMenuEvent(true, eContextMenu, this,
WidgetMouseEvent::eReal,
WidgetMouseEvent::eContextMenuKey);
if (MaybeDispatchContextMenuEvent(aEvent)) {
return TRUE;
}
contextMenuEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
contextMenuEvent.AssignEventTime(GetWidgetEventTime(aEvent->time));
contextMenuEvent.mClickCount = 1;
KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
DispatchInputEvent(&contextMenuEvent);
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
nsresult rv = dispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
return TRUE;
}
// If the character code is in the BMP, send the key press event.
// Otherwise, send a compositionchange event with the equivalent UTF-16
// string.
// TODO: Investigate other browser's behavior in this case because
// this hack is odd for UI Events.
nsEventStatus status = nsEventStatus_eIgnore;
if (keypressEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
keypressEvent.mKeyValue.Length() == 1) {
dispatcher->MaybeDispatchKeypressEvents(keypressEvent,
status, aEvent);
} else {
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
nsresult rv = dispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
return TRUE;
}
// If the character code is in the BMP, send the key press event.
// Otherwise, send a compositionchange event with the equivalent UTF-16
// string.
// TODO: Investigate other browser's behavior in this case because
// this hack is odd for UI Events.
nsEventStatus status = nsEventStatus_eIgnore;
if (keypressEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
keypressEvent.mKeyValue.Length() == 1) {
dispatcher->MaybeDispatchKeypressEvents(keypressEvent,
status, aEvent);
} else {
WidgetEventTime eventTime = GetWidgetEventTime(aEvent->time);
dispatcher->CommitComposition(status, &keypressEvent.mKeyValue,
&eventTime);
}
WidgetEventTime eventTime = GetWidgetEventTime(aEvent->time);
dispatcher->CommitComposition(status, &keypressEvent.mKeyValue,
&eventTime);
}
return TRUE;
}
bool
nsWindow::MaybeDispatchContextMenuEvent(const GdkEventKey* aEvent)
{
KeyNameIndex keyNameIndex = KeymapWrapper::ComputeDOMKeyNameIndex(aEvent);
// Shift+F10 and ContextMenu should cause eContextMenu event.
if (keyNameIndex != KEY_NAME_INDEX_F10 &&
keyNameIndex != KEY_NAME_INDEX_ContextMenu) {
return false;
}
WidgetMouseEvent contextMenuEvent(true, eContextMenu, this,
WidgetMouseEvent::eReal,
WidgetMouseEvent::eContextMenuKey);
contextMenuEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
contextMenuEvent.AssignEventTime(GetWidgetEventTime(aEvent->time));
contextMenuEvent.mClickCount = 1;
KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
if (contextMenuEvent.IsControl() || contextMenuEvent.IsMeta() ||
contextMenuEvent.IsAlt()) {
return false;
}
// If the key is ContextMenu, then an eContextMenu mouse event is
// dispatched regardless of the state of the Shift modifier. When it is
// pressed without the Shift modifier, a web page can prevent the default
// context menu action. When pressed with the Shift modifier, the web page
// cannot prevent the default context menu action.
// (PresShell::HandleEventInternal() sets mOnlyChromeDispatch to true.)
// If the key is F10, it needs Shift state because Shift+F10 is well-known
// shortcut key on Linux. However, eContextMenu with Shift state is
// special. It won't fire "contextmenu" event in the web content for
// blocking web page to prevent its default. Therefore, this combination
// should work same as ContextMenu key.
// XXX Should we allow to block web page to prevent its default with
// Ctrl+Shift+F10 or Alt+Shift+F10 instead?
if (keyNameIndex == KEY_NAME_INDEX_F10) {
if (!contextMenuEvent.IsShift()) {
return false;
}
contextMenuEvent.mModifiers &= ~MODIFIER_SHIFT;
}
DispatchInputEvent(&contextMenuEvent);
return true;
}
gboolean
nsWindow::OnKeyReleaseEvent(GdkEventKey *aEvent)
{
@ -5981,17 +6021,6 @@ get_inner_gdk_window (GdkWindow *aWindow,
return aWindow;
}
static inline bool
is_context_menu_key(const WidgetKeyboardEvent& aKeyEvent)
{
return ((aKeyEvent.mKeyCode == NS_VK_F10 && aKeyEvent.IsShift() &&
!aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
!aKeyEvent.IsAlt()) ||
(aKeyEvent.mKeyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.IsShift() &&
!aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
!aKeyEvent.IsAlt()));
}
static int
is_parent_ungrab_enter(GdkEventCrossing *aEvent)
{

Просмотреть файл

@ -192,6 +192,19 @@ public:
void OnContainerFocusOutEvent(GdkEventFocus *aEvent);
gboolean OnKeyPressEvent(GdkEventKey *aEvent);
gboolean OnKeyReleaseEvent(GdkEventKey *aEvent);
/**
* MaybeDispatchContextMenuEvent() may dispatch eContextMenu event if
* the given key combination should cause opening context menu.
*
* @param aEvent The native key event.
* @return true if this method dispatched eContextMenu
* event. Otherwise, false.
* Be aware, when this returns true, the
* widget may have been destroyed.
*/
bool MaybeDispatchContextMenuEvent(const GdkEventKey* aEvent);
void OnScrollEvent(GdkEventScroll *aEvent);
void OnVisibilityNotifyEvent(GdkEventVisibility *aEvent);
void OnWindowStateEvent(GtkWidget *aWidget,