From e7d5fd30562726d69d90d36803450f0de3d59c4e Mon Sep 17 00:00:00 2001 From: Xi Yan Date: Thu, 2 Aug 2018 13:08:25 -0400 Subject: Bug 537025 - SWT + GTK3 + Sending key events programmatically Fixed regression from Bug 302171 where sending modifier as a separate key event does not work. Sending GDK_KEY_PRESS event using gdk_test_simulate_key will not hold key down infinitely until a GDK_KEY_RELEASE event is sent. The modifier is cached in case modifiers are sent in separate event to Display.post(). Tested using attached snippet and Snippet146. Change-Id: I2c9b617345b3f92c3a32299e64ce7f1ce5ef7992 Signed-off-by: Xi Yan --- .../gtk/org/eclipse/swt/widgets/Display.java | 31 ++- .../tests/gtk/snippets/Bug537025_SendKeyEvent.java | 231 +++++++++++++++++++++ 2 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug537025_SendKeyEvent.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java index 68b5de99d6..9353253272 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java @@ -443,6 +443,9 @@ public class Display extends Device { }; + /* Cache pressed modifier. See Bug 537025. */ + int cachedModifier = 0; + /* Latin layout key group */ private int latinKeyGroup; @@ -4421,6 +4424,22 @@ public boolean post (Event event) { switch (type) { case SWT.KeyDown: case SWT.KeyUp: { + int pressedModifier = 0; + switch (event.keyCode) { + case SWT.SHIFT: pressedModifier = GDK.GDK_SHIFT_MASK; break; + case SWT.ALT: pressedModifier = GDK.GDK_MOD1_MASK; break; + case SWT.CONTROL: pressedModifier = GDK.GDK_CONTROL_MASK; break; + case SWT.ALT_GR: pressedModifier = GDK.GDK_MOD5_MASK; break; + default: + pressedModifier = 0; + } + if (pressedModifier != 0) { + if (type == SWT.KeyDown) { + cachedModifier |= pressedModifier; + } else { + cachedModifier &= ~pressedModifier; + } + } int keysym = untranslateKey (event.keyCode); if (keysym == 0) { char key = event.character; @@ -4436,14 +4455,14 @@ public boolean post (Event event) { } if (keysym == 0) return false; } - int modifier = 0; + int modifier = cachedModifier; switch (event.stateMask) { - case SWT.SHIFT: modifier = GDK.GDK_SHIFT_MASK; break; - case SWT.ALT: modifier = GDK.GDK_MOD1_MASK; break; - case SWT.CONTROL: modifier = GDK.GDK_CONTROL_MASK; break; - case SWT.ALT_GR: modifier = GDK.GDK_MOD5_MASK; break; + case SWT.SHIFT: modifier = cachedModifier | GDK.GDK_SHIFT_MASK; break; + case SWT.ALT: modifier = cachedModifier | GDK.GDK_MOD1_MASK; break; + case SWT.CONTROL: modifier = cachedModifier | GDK.GDK_CONTROL_MASK; break; + case SWT.ALT_GR: modifier = cachedModifier | GDK.GDK_MOD5_MASK; break; default: - modifier = 0; + modifier = cachedModifier; } GDK.gdk_test_simulate_key(gdkWindow, x[0], y[0], keysym, modifier, type == SWT.KeyDown ? GDK.GDK_KEY_PRESS: GDK.GDK_KEY_RELEASE); return true; diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug537025_SendKeyEvent.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug537025_SendKeyEvent.java new file mode 100644 index 0000000000..4d164c05f7 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug537025_SendKeyEvent.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Widget; + +public class Bug537025_SendKeyEvent { + + protected static final String SHELL_TITLE = "Keyboard testing shell"; + private Text text; + private final Display display; + private final Shell shell; + + public Bug537025_SendKeyEvent() { + display = Display.getDefault(); + shell = new Shell(display, SWT.CLOSE); + createShell(); + + shell.addListener(SWT.CLOSE, arg0 -> { + System.out.println("Main Shell handling Close event, about to dipose the main Display"); + display.dispose(); + }); + + addClearButton(); + addTestButtons(); + addLeftButton(); + addNoModButton(); + + while (!display.isDisposed()) { + try { + if (!display.readAndDispatch()) { + display.sleep(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + System.out.println("Test finished"); + } + + public void addNoModButton() { + Button noMod = new Button(shell, SWT.PUSH); + noMod.setText("Press 'a' with no Shift"); + noMod.setBounds(10, 150, 150, 30); + noMod.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + testNoMod(); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + testNoMod(); + + } + + }); + } + + public void addLeftButton() { + Button left = new Button(shell, SWT.PUSH); + left.setText("To the Left"); + left.setBounds(10, 120, 150, 30); + left.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + testTypeLeft(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetDefaultSelected(e); + } + + }); + } + + public void addClearButton() { + Button spawn = new Button(shell, SWT.PUSH); + spawn.setText("Clear text"); + spawn.setBounds(10, 30, 150, 30); + spawn.addSelectionListener(new SelectionListener() { + + @Override + public void widgetDefaultSelected(SelectionEvent arg0) { + text.setText(""); + } + + @Override + public void widgetSelected(SelectionEvent arg0) { + widgetDefaultSelected(arg0); + } + + }); + } + + public void addTestButtons() { + Button spawn = new Button(shell, SWT.PUSH); + spawn.setText("Test type one by one"); + spawn.setBounds(10, 60, 150, 30); + spawn.addSelectionListener(new SelectionListener() { + + @Override + public void widgetDefaultSelected(SelectionEvent arg0) { + testTypeOneByOne(); + } + + @Override + public void widgetSelected(SelectionEvent arg0) { + widgetDefaultSelected(arg0); + } + }); + + Button spawn2 = new Button(shell, SWT.PUSH); + spawn2.setText("Test type with mask"); + spawn2.setBounds(10, 90, 150, 30); + spawn2.addSelectionListener(new SelectionListener() { + + @Override + public void widgetDefaultSelected(SelectionEvent arg0) { + testTypeWithMask(); + } + + @Override + public void widgetSelected(SelectionEvent arg0) { + widgetDefaultSelected(arg0); + } + }); + } + + public void createShell() { + shell.setText(SHELL_TITLE); + shell.setLayout(new RowLayout(SWT.VERTICAL)); + shell.setSize(500, 500); + shell.open(); + shell.setFocus(); + text = new Text(shell, SWT.NONE); + text.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); + shell.layout(); + } + + public void testTypeOneByOne() { + text.setFocus(); + Event shiftDown = keyDown(SWT.SHIFT); + Event shiftUp = keyUp(SWT.SHIFT); + Event a = keyDown('a'); + Event aUp = keyUp('a'); + + postEvent(shiftDown); + postEvent(a); + postEvent(aUp); + postEvent(shiftUp); + } + + public void testTypeLeft() { + text.setFocus(); + Event leftDown = keyDown(SWT.ARROW_LEFT); + Event leftUp = keyUp(SWT.ARROW_LEFT); + postEvent(leftDown); + postEvent(leftUp); + } + + public void testNoMod() { + text.setFocus(); + Event aDown = keyDown('a'); + Event aUp = keyUp('a'); + postEvent(aDown); + postEvent(aUp); + } + + public void testTypeWithMask() { + text.setFocus(); + Event a = keyDown('a'); + a.stateMask = SWT.SHIFT; + Event aUp = keyUp('a'); + postEvent(a); + postEvent(aUp); + } + + public Event keyDown(final int key) { + return keyEvent(key, SWT.KeyDown, getFocusControl()); + } + + public Event keyUp(final int key) { + return keyEvent(key, SWT.KeyUp, getFocusControl()); + } + + public void postEvent(Event e) { + org.eclipse.swt.widgets.Display.getDefault().post(e); + } + + public Control getFocusControl() { + return org.eclipse.swt.widgets.Display.getDefault().getFocusControl(); + } + + public Event keyEvent(int key, int type, Widget w) { + Event e = new Event(); + e.keyCode = key; + e.character = (char) key; + e.type = type; + e.widget = w; + return e; + } + + public static void main(String[] args) { + new Bug537025_SendKeyEvent(); + System.exit(0); + } + +} \ No newline at end of file -- cgit v1.2.3