summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java86
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java664
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java88
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Control.java122
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Tracker.java628
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Widget.java121
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java458
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java632
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java497
9 files changed, 1800 insertions, 1496 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
index 78990bf1c8..5389ac5272 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
@@ -1856,7 +1856,7 @@ int /*long*/ gtk_key_press_event (int /*long*/ widget, int /*long*/ event) {
if (translateTraversal (gdkEvent)) return 1;
// widget could be disposed at this point
if (isDisposed ()) return 0;
- return sendKeyEvent (SWT.KeyDown, gdkEvent) ? 0 : 1;
+ return super.gtk_key_press_event (widget, event);
}
int /*long*/ gtk_key_release_event (int /*long*/ widget, int /*long*/ event) {
@@ -1865,9 +1865,7 @@ int /*long*/ gtk_key_release_event (int /*long*/ widget, int /*long*/ event) {
if (imHandle != 0) {
if (OS.gtk_im_context_filter_keypress (imHandle, event)) return 1;
}
- GdkEventKey gdkEvent = new GdkEventKey ();
- OS.memmove (gdkEvent, event, GdkEventKey.sizeof);
- return sendKeyEvent (SWT.KeyUp, gdkEvent) ? 0 : 1;
+ return super.gtk_key_release_event (widget, event);
}
int /*long*/ gtk_leave_notify_event (int /*long*/ widget, int /*long*/ event) {
@@ -2309,86 +2307,6 @@ boolean sendHelpEvent (int /*long*/ helpType) {
return false;
}
-char [] sendIMKeyEvent (int type, GdkEventKey keyEvent, char [] chars) {
- int index = 0, count = 0, state = 0, time = 0;
- if (keyEvent == null) {
- int /*long*/ ptr = OS.gtk_get_current_event ();
- if (ptr != 0) {
- keyEvent = new GdkEventKey ();
- OS.memmove (keyEvent, ptr, GdkEventKey.sizeof);
- OS.gdk_event_free (ptr);
- switch (keyEvent.type) {
- case OS.GDK_KEY_PRESS:
- case OS.GDK_KEY_RELEASE:
- state = keyEvent.state;
- time = keyEvent.time;
- break;
- default:
- keyEvent = null;
- break;
- }
- }
- }
- if (keyEvent == null) {
- int [] buffer = new int [1];
- OS.gtk_get_current_event_state (buffer);
- state = buffer [0];
- time = OS.gtk_get_current_event_time();
- }
- while (index < chars.length) {
- Event event = new Event ();
- event.time = time;
- if (keyEvent != null && keyEvent.length <= 1) {
- setKeyState (event, keyEvent);
- } else {
- setInputState (event, state);
- }
- event.character = chars [index];
- sendEvent (type, event);
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the key
- * events. If this happens, end the processing of
- * the key by returning null.
- */
- if (isDisposed ()) return null;
- if (event.doit) chars [count++] = chars [index];
- index++;
- }
- if (count == 0) return null;
- if (index != count) {
- char [] result = new char [count];
- System.arraycopy (chars, 0, result, 0, count);
- return result;
- }
- return chars;
-}
-
-boolean sendKeyEvent (int type, GdkEventKey keyEvent) {
- int length = keyEvent.length;
- if (length <= 1) {
- Event event = new Event ();
- event.time = keyEvent.time;
- if (!setKeyState (event, keyEvent)) return true;
- sendEvent (type, event);
- // widget could be disposed at this point
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the key
- * events. If this happens, end the processing of
- * the key by returning false.
- */
- if (isDisposed ()) return false;
- return event.doit;
- }
- byte [] buffer = new byte [length];
- OS.memmove (buffer, keyEvent.string, length);
- char [] chars = Converter.mbcsToWcs (null, buffer);
- return sendIMKeyEvent (type, keyEvent, chars) != null;
-}
-
void sendMouseEvent (int type, int button, int /*long*/ eventPtr) {
Event event = new Event ();
event.time = OS.gdk_event_get_time (eventPtr);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java
index 6e6f340d3c..60bb053aae 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java
@@ -37,11 +37,13 @@ import org.eclipse.swt.events.*;
*/
public class Tracker extends Widget {
Composite parent;
- int /*long*/ cursor, lastCursor;
- boolean tracking, stippled;
+ int /*long*/ cursor, lastCursor, window;
+ boolean tracking, cancelled, grabbed, stippled;
Rectangle [] rectangles, proportions;
Rectangle bounds;
int cursorOrientation = SWT.NONE;
+ int oldX, oldY;
+
final static int STEPSIZE_SMALL = 1;
final static int STEPSIZE_LARGE = 9;
@@ -154,6 +156,81 @@ public void addControlListener(ControlListener listener) {
}
/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard, by sending
+ * it one of the messages defined in the <code>KeyListener</code>
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see KeyListener
+ * @see #removeKeyListener
+ */
+public void addKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.KeyUp,typedListener);
+ addListener(SWT.KeyDown,typedListener);
+}
+
+Point adjustMoveCursor () {
+ int newX = bounds.x + bounds.width / 2;
+ int newY = bounds.y;
+
+ display.setCursorLocation (newX, newY);
+
+ /*
+ * The call to XWarpPointer does not always place the pointer on the
+ * exact location that is specified, so do a query (below) to get the
+ * actual location of the pointer after it has been moved.
+ */
+ int [] actualX = new int [1], actualY = new int [1], state = new int [1];
+ OS.gdk_window_get_pointer (window, actualX, actualY, state);
+ return new Point (actualX [0], actualY [0]);
+}
+
+Point adjustResizeCursor () {
+ int newX, newY;
+
+ if ((cursorOrientation & SWT.LEFT) != 0) {
+ newX = bounds.x;
+ } else if ((cursorOrientation & SWT.RIGHT) != 0) {
+ newX = bounds.x + bounds.width;
+ } else {
+ newX = bounds.x + bounds.width / 2;
+ }
+
+ if ((cursorOrientation & SWT.UP) != 0) {
+ newY = bounds.y;
+ } else if ((cursorOrientation & SWT.DOWN) != 0) {
+ newY = bounds.y + bounds.height;
+ } else {
+ newY = bounds.y + bounds.height / 2;
+ }
+
+ display.setCursorLocation (newX, newY);
+
+ /*
+ * The call to XWarpPointer does not always place the pointer on the
+ * exact location that is specified, so do a query (below) to get the
+ * actual location of the pointer after it has been moved.
+ */
+ int [] actualX = new int [1], actualY = new int [1], state = new int [1];
+ OS.gdk_window_get_pointer (window, actualX, actualY, state);
+ return new Point (actualX [0], actualY [0]);
+}
+
+
+/**
* Stops displaying the tracker rectangles. Note that this is not considered
* to be a cancelation by the user.
*
@@ -280,6 +357,257 @@ public boolean getStippled () {
return stippled;
}
+boolean grab () {
+ int result = OS.gdk_pointer_grab (window, false, OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_RELEASE_MASK, window, cursor, OS.GDK_CURRENT_TIME);
+ return result == OS.GDK_GRAB_SUCCESS;
+}
+
+int /*long*/ gtk_button_release_event (int /*long*/ widget, int /*long*/ event) {
+ return gtk_mouse (OS.GDK_BUTTON_RELEASE, widget, event);
+}
+
+int /*long*/ gtk_key_press_event (int /*long*/ widget, int /*long*/ eventPtr) {
+ int /*long*/ result = super.gtk_key_press_event (widget, eventPtr);
+ if (result != 0) return result;
+ GdkEventKey keyEvent = new GdkEventKey ();
+ OS.memmove (keyEvent, eventPtr, GdkEventKey.sizeof);
+ int stepSize = ((keyEvent.state & OS.GDK_CONTROL_MASK) != 0) ? STEPSIZE_SMALL : STEPSIZE_LARGE;
+ int xChange = 0, yChange = 0;
+ switch (keyEvent.keyval) {
+ case OS.GDK_Escape:
+ cancelled = true;
+ // fallthrough
+ case OS.GDK_Return:
+ tracking = false;
+ break;
+ case OS.GDK_Left:
+ xChange = -stepSize;
+ break;
+ case OS.GDK_Right:
+ xChange = stepSize;
+ break;
+ case OS.GDK_Up:
+ yChange = -stepSize;
+ break;
+ case OS.GDK_Down:
+ yChange = stepSize;
+ break;
+ }
+ if (xChange != 0 || yChange != 0) {
+ Rectangle [] oldRectangles = rectangles;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ event.x = oldX + xChange;
+ event.y = oldY + yChange;
+ if ((style & SWT.RESIZE) != 0) {
+ resizeRectangles (xChange, yChange);
+ sendEvent (SWT.Resize, event);
+ /*
+ * It is possible (but unlikely) that application
+ * code could have disposed the widget in the resize
+ * event. If this happens return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase);
+ drawRectangles (rectangles);
+ }
+ Point cursorPos = adjustResizeCursor ();
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+ } else {
+ moveRectangles (xChange, yChange);
+ sendEvent (SWT.Move, event);
+ /*
+ * It is possible (but unlikely) that application
+ * code could have disposed the widget in the move
+ * event. If this happens return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase);
+ drawRectangles (rectangles);
+ }
+ Point cursorPos = adjustMoveCursor ();
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+ }
+ }
+ return result;
+}
+
+int /*long*/ gtk_motion_notify_event (int /*long*/ widget, int /*long*/ eventPtr) {
+ if (cursor != lastCursor) {
+ ungrab ();
+ grabbed = grab ();
+ }
+ return gtk_mouse (OS.GDK_MOTION_NOTIFY, widget, eventPtr);
+}
+
+int /*long*/ gtk_mouse (int eventType, int /*long*/ widget, int /*long*/ eventPtr) {
+ int [] newX = new int [1], newY = new int [1];
+ OS.gdk_window_get_pointer (window, newX, newY, null);
+ if (oldX != newX [0] || oldY != newY [0]) {
+ Rectangle [] oldRectangles = rectangles;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ if (parent == null) {
+ event.x = newX [0];
+ event.y = newY [0];
+ } else {
+ Point screenCoord = display.map (parent, null, newX [0], newY [0]);
+ event.x = screenCoord.x;
+ event.y = screenCoord.y;
+ }
+ if ((style & SWT.RESIZE) != 0) {
+ resizeRectangles (newX [0] - oldX, newY [0] - oldY);
+ sendEvent (SWT.Resize, event);
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the resize
+ * event. If this happens, return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase);
+ drawRectangles (rectangles);
+ }
+ Point cursorPos = adjustResizeCursor ();
+ newX [0] = cursorPos.x;
+ newY [0] = cursorPos.y;
+ } else {
+ moveRectangles (newX [0] - oldX, newY [0] - oldY);
+ sendEvent (SWT.Move, event);
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the move
+ * event. If this happens, return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase);
+ drawRectangles (rectangles);
+ }
+ }
+ oldX = newX [0];
+ oldY = newY [0];
+ }
+ tracking = eventType != OS.GDK_BUTTON_RELEASE;
+ return 0;
+}
+
void moveRectangles (int xChange, int yChange) {
if (xChange < 0 && ((style & SWT.LEFT) == 0)) xChange = 0;
if (xChange > 0 && ((style & SWT.RIGHT) == 0)) xChange = 0;
@@ -308,12 +636,12 @@ void moveRectangles (int xChange, int yChange) {
public boolean open () {
checkWidget();
if (rectangles == null) return false;
- int /*long*/ window = OS.GDK_ROOT_PARENT ();
+ window = OS.GDK_ROOT_PARENT ();
if (parent != null) {
window = OS.GTK_WIDGET_WINDOW (parent.paintHandle());
}
if (window == 0) return false;
- boolean cancelled = false;
+ cancelled = false;
tracking = true;
drawRectangles (rectangles);
int [] oldX = new int [1], oldY = new int [1], state = new int [1];
@@ -332,34 +660,26 @@ public boolean open () {
cursorOrientation |= hStyle;
}
- /*
- * The following is intentionally commented. Since gtk does not currently
- * support pointer warping, the resize cursor cannot be adjusted. If this
- * capability is added in the future then the following should be uncommented,
- * and the #adjustResizeCursor method can be copied from another platform.
- */
-// Point cursorPos;
-// int mask = OS.GDK_BUTTON1_MASK | OS.GDK_BUTTON2_MASK | OS.GDK_BUTTON3_MASK;
-// boolean mouseDown = (state [0] & mask) != 0;
-// if (!mouseDown) {
-// if ((style & SWT.RESIZE) != 0) {
-// cursorPos = adjustResizeCursor (xDisplay, xWindow);
-// } else {
-// cursorPos = adjustMoveCursor (xDisplay, xWindow);
-// }
-// oldX [0] = cursorPos.x; oldY [0] = cursorPos.y;
-// }
+ Point cursorPos;
+ int mask = OS.GDK_BUTTON1_MASK | OS.GDK_BUTTON2_MASK | OS.GDK_BUTTON3_MASK;
+ boolean mouseDown = (state [0] & mask) != 0;
+ if (!mouseDown) {
+ if ((style & SWT.RESIZE) != 0) {
+ cursorPos = adjustResizeCursor ();
+ } else {
+ cursorPos = adjustMoveCursor ();
+ }
+ oldX [0] = cursorPos.x;
+ oldY [0] = cursorPos.y;
+ }
+ this.oldX = oldX [0];
+ this.oldY = oldY [0];
- GdkEvent gdkEvent = new GdkEvent();
- GdkEventKey keyEvent = new GdkEventKey ();
- int [] newX = new int [1], newY = new int [1];
- int grabMask = OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_RELEASE_MASK;
- int ptrGrabResult = OS.gdk_pointer_grab (window, false, grabMask, window, cursor, OS.GDK_CURRENT_TIME);
+ grabbed = grab ();
lastCursor = cursor;
- /*
- * Tracker behaves like a Dialog with its own OS event loop.
- */
+ /* Tracker behaves like a Dialog with its own OS event loop. */
+ GdkEvent gdkEvent = new GdkEvent();
while (tracking) {
if (parent != null && parent.isDisposed ()) break;
int /*long*/ eventPtr;
@@ -372,257 +692,15 @@ public boolean open () {
}
}
OS.memmove (gdkEvent, eventPtr, GdkEvent.sizeof);
- int eventType = gdkEvent.type;
- switch (eventType) {
- case OS.GDK_MOTION_NOTIFY:
- if (cursor != lastCursor) {
- if (ptrGrabResult == OS.GDK_GRAB_SUCCESS) OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
- ptrGrabResult = OS.gdk_pointer_grab (window, false, grabMask, window, cursor, OS.GDK_CURRENT_TIME);
- }
- // fall through
- case OS.GDK_BUTTON_RELEASE:
- OS.gdk_window_get_pointer (window, newX, newY, null);
- if (oldX [0] != newX [0] || oldY [0] != newY [0]) {
- Rectangle [] oldRectangles = rectangles;
- Rectangle [] rectsToErase = new Rectangle [rectangles.length];
- for (int i = 0; i < rectangles.length; i++) {
- Rectangle current = rectangles [i];
- rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
- }
- Event event = new Event ();
- if (parent == null) {
- event.x = newX [0];
- event.y = newY [0];
- } else {
- Point screenCoord = display.map (parent, null, newX [0], newY [0]);
- event.x = screenCoord.x;
- event.y = screenCoord.y;
- }
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (newX [0] - oldX [0], newY [0] - oldY [0]);
- sendEvent (SWT.Resize, event);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the resize event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase);
- drawRectangles (rectangles);
- }
- /*
- * The following is intentionally commented. Since gtk does not currently
- * support pointer warping, the resize cursor cannot be adjusted. If this
- * capability is added in the future then the following should be uncommented,
- * and the #adjustResizeCursor method can be copied from another platform.
- */
-// Point cursorPos = adjustResizeCursor ();
- } else {
- moveRectangles (newX [0] - oldX [0], newY [0] - oldY [0]);
- sendEvent (SWT.Move, event);
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the move
- * event. If this happens, return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the move event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase);
- drawRectangles (rectangles);
- }
- }
- oldX [0] = newX [0]; oldY [0] = newY [0];
- }
- tracking = eventType != OS.GDK_BUTTON_RELEASE;
- break;
- case OS.GDK_KEY_PRESS:
- OS.memmove (keyEvent, eventPtr, GdkEventKey.sizeof);
- int stepSize = ((keyEvent.state & OS.GDK_CONTROL_MASK) != 0) ? STEPSIZE_SMALL : STEPSIZE_LARGE;
- int xChange = 0, yChange = 0;
- switch (keyEvent.keyval) {
- case OS.GDK_Escape:
- cancelled = true;
- // fallthrough
- case OS.GDK_Return:
- tracking = false;
- break;
- case OS.GDK_Left:
- xChange = -stepSize;
- break;
- case OS.GDK_Right:
- xChange = stepSize;
- break;
- case OS.GDK_Up:
- yChange = -stepSize;
- break;
- case OS.GDK_Down:
- yChange = stepSize;
- break;
- }
- if (xChange != 0 || yChange != 0) {
- Rectangle [] oldRectangles = rectangles;
- Rectangle [] rectsToErase = new Rectangle [rectangles.length];
- for (int i = 0; i < rectangles.length; i++) {
- Rectangle current = rectangles [i];
- rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
- }
- Event event = new Event ();
- event.x = oldX [0] + xChange;
- event.y = oldY [0] + yChange;
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (xChange, yChange);
- sendEvent (SWT.Resize, event);
- /*
- * It is possible (but unlikely) that application
- * code could have disposed the widget in the resize
- * event. If this happens return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the resize event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase);
- drawRectangles (rectangles);
- }
- /*
- * The following is intentionally commented. Since gtk does not currently
- * support pointer warping, the resize cursor cannot be adjusted. If this
- * capability is added in the future then the following should be uncommented,
- * and the #adjustResizeCursor method can be copied from another platform.
- */
-// cursorPos = adjustResizeCursor (xDisplay, xWindow);
-// oldX[0] = cursorPos.x; oldY[0] = cursorPos.y;
- } else {
- moveRectangles (xChange, yChange);
- sendEvent (SWT.Move, event);
- /*
- * It is possible (but unlikely) that application
- * code could have disposed the widget in the move
- * event. If this happens return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the move event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase);
- drawRectangles (rectangles);
- }
- /*
- * The following is intentionally commented. Since gtk does not currently
- * support pointer warping, the move cursor cannot be adjusted. If this
- * capability is added in the future then the following should be uncommented,
- * and the #adjustMoveCursor method can be copied from another platform.
- */
-// cursorPos = adjustMoveCursor (xDisplay, xWindow);
-// oldX[0] = cursorPos.x; oldY[0] = cursorPos.y;
- }
- }
- break;
+ int /*long*/ widget = OS.gtk_get_event_widget (eventPtr);
+ switch (gdkEvent.type) {
+ case OS.GDK_MOTION_NOTIFY: gtk_motion_notify_event (widget, eventPtr); break;
+ case OS.GDK_BUTTON_RELEASE: gtk_button_release_event (widget, eventPtr); break;
+ case OS.GDK_KEY_PRESS: gtk_key_press_event (widget, eventPtr); break;
+ case OS.GDK_KEY_RELEASE: gtk_key_release_event (widget, eventPtr); break;
case OS.GDK_BUTTON_PRESS:
case OS.GDK_2BUTTON_PRESS:
case OS.GDK_3BUTTON_PRESS:
- case OS.GDK_KEY_RELEASE:
case OS.GDK_ENTER_NOTIFY:
case OS.GDK_LEAVE_NOTIFY:
/* Do not dispatch these */
@@ -633,7 +711,8 @@ public boolean open () {
OS.gdk_event_free (eventPtr);
}
if (!isDisposed ()) drawRectangles (rectangles);
- if (ptrGrabResult == OS.GDK_GRAB_SUCCESS) OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
+ ungrab ();
+ window = 0;
return !cancelled;
}
@@ -662,6 +741,31 @@ public void removeControlListener (ControlListener listener) {
eventTable.unhook (SWT.Move, listener);
}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see KeyListener
+ * @see #addKeyListener
+ */
+public void removeKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.KeyUp, listener);
+ eventTable.unhook (SWT.KeyDown, listener);
+}
+
void resizeRectangles (int xChange, int yChange) {
/*
* If the cursor orientation has not been set in the orientation of
@@ -829,4 +933,8 @@ public void setStippled (boolean stippled) {
this.stippled = stippled;
}
+void ungrab () {
+ if (grabbed) OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
+}
+
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
index 344c57bab8..4148acc376 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
@@ -580,11 +580,15 @@ int /*long*/ gtk_insert_text (int /*long*/ widget, int /*long*/ new_text, int /*
}
int /*long*/ gtk_key_press_event (int /*long*/ widget, int /*long*/ event) {
- return 0;
+ GdkEventKey gdkEvent = new GdkEventKey ();
+ OS.memmove (gdkEvent, event, GdkEventKey.sizeof);
+ return sendKeyEvent (SWT.KeyDown, gdkEvent) ? 0 : 1;
}
int /*long*/ gtk_key_release_event (int /*long*/ widget, int /*long*/ event) {
- return 0;
+ GdkEventKey gdkEvent = new GdkEventKey ();
+ OS.memmove (gdkEvent, event, GdkEventKey.sizeof);
+ return sendKeyEvent (SWT.KeyUp, gdkEvent) ? 0 : 1;
}
int /*long*/ gtk_leave_notify_event (int /*long*/ widget, int /*long*/ event) {
@@ -1000,6 +1004,86 @@ void sendEvent (int eventType, Event event, boolean send) {
}
}
+boolean sendKeyEvent (int type, GdkEventKey keyEvent) {
+ int length = keyEvent.length;
+ if (length <= 1) {
+ Event event = new Event ();
+ event.time = keyEvent.time;
+ if (!setKeyState (event, keyEvent)) return true;
+ sendEvent (type, event);
+ // widget could be disposed at this point
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the key
+ * events. If this happens, end the processing of
+ * the key by returning false.
+ */
+ if (isDisposed ()) return false;
+ return event.doit;
+ }
+ byte [] buffer = new byte [length];
+ OS.memmove (buffer, keyEvent.string, length);
+ char [] chars = Converter.mbcsToWcs (null, buffer);
+ return sendIMKeyEvent (type, keyEvent, chars) != null;
+}
+
+char [] sendIMKeyEvent (int type, GdkEventKey keyEvent, char [] chars) {
+ int index = 0, count = 0, state = 0, time = 0;
+ if (keyEvent == null) {
+ int /*long*/ ptr = OS.gtk_get_current_event ();
+ if (ptr != 0) {
+ keyEvent = new GdkEventKey ();
+ OS.memmove (keyEvent, ptr, GdkEventKey.sizeof);
+ OS.gdk_event_free (ptr);
+ switch (keyEvent.type) {
+ case OS.GDK_KEY_PRESS:
+ case OS.GDK_KEY_RELEASE:
+ state = keyEvent.state;
+ time = keyEvent.time;
+ break;
+ default:
+ keyEvent = null;
+ break;
+ }
+ }
+ }
+ if (keyEvent == null) {
+ int [] buffer = new int [1];
+ OS.gtk_get_current_event_state (buffer);
+ state = buffer [0];
+ time = OS.gtk_get_current_event_time();
+ }
+ while (index < chars.length) {
+ Event event = new Event ();
+ event.time = time;
+ if (keyEvent != null && keyEvent.length <= 1) {
+ setKeyState (event, keyEvent);
+ } else {
+ setInputState (event, state);
+ }
+ event.character = chars [index];
+ sendEvent (type, event);
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the key
+ * events. If this happens, end the processing of
+ * the key by returning null.
+ */
+ if (isDisposed ()) return null;
+ if (event.doit) chars [count++] = chars [index];
+ index++;
+ }
+ if (count == 0) return null;
+ if (index != count) {
+ char [] result = new char [count];
+ System.arraycopy (chars, 0, result, 0, count);
+ return result;
+ }
+ return chars;
+}
+
/**
* Sets the application defined widget data associated
* with the receiver to be the argument. The <em>widget
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Control.java
index 1a08b9f572..0eb1e7b6b2 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Control.java
@@ -11,7 +11,6 @@
package org.eclipse.swt.widgets;
-import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.motif.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
@@ -1705,106 +1704,6 @@ void sendHelpEvent (int callData) {
control = control.parent;
}
}
-boolean sendIMKeyEvent (int type, XKeyEvent xEvent) {
- return sendIMKeyEvent (type, xEvent, 0);
-}
-boolean sendIMKeyEvent (int type, XKeyEvent xEvent, int textHandle) {
- /*
- * Bug in Motif. On Linux only, XmImMbLookupString () does not return
- * XBufferOverflow as the status if the buffer is too small. The fix
- * is to pass a large buffer.
- */
- byte [] buffer = new byte [512];
- int [] status = new int [1], unused = new int [1];
- int focusHandle = OS.XtWindowToWidget (xEvent.display, xEvent.window);
- int length = OS.XmImMbLookupString (focusHandle, xEvent, buffer, buffer.length, unused, status);
- if (status [0] == OS.XBufferOverflow) {
- buffer = new byte [length];
- length = OS.XmImMbLookupString (focusHandle, xEvent, buffer, length, unused, status);
- }
- if (length == 0) return true;
-
- /* Convert from MBCS to UNICODE and send the event */
- /* Use the character encoding for the default locale */
- char [] chars = Converter.mbcsToWcs (null, buffer);
- int index = 0, count = 0;
- while (index < chars.length) {
- if (chars [index] == 0) {
- chars [count] = 0;
- break;
- }
- Event event = new Event ();
- event.time = xEvent.time;
- event.character = chars [index];
- setInputState (event, xEvent.state);
- sendEvent (type, event);
- // widget could be disposed at this point
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the key
- * events. If this happens, end the processing of
- * the key by returning false.
- */
- if (isDisposed ()) return false;
- if (event.doit) chars [count++] = chars [index];
- index++;
- }
- if (count == 0) return false;
- if (textHandle != 0) {
- /*
- * Bug in Motif. On Solaris and Linux, XmImMbLookupString() clears
- * the characters from the IME. This causes the characters to be
- * stolen from the text widget. The fix is to detect that the IME
- * has been cleared and use XmTextInsert() to insert the stolen
- * characters. This problem does not happen on AIX.
- */
- byte [] testBuffer = new byte [5];
- int testLength = OS.XmImMbLookupString (textHandle, xEvent, testBuffer, testBuffer.length, unused, unused);
- if (testLength == 0 || index != count) {
- int [] start = new int [1], end = new int [1];
- OS.XmTextGetSelectionPosition (textHandle, start, end);
- if (start [0] == end [0]) {
- start [0] = end [0] = OS.XmTextGetInsertionPosition (textHandle);
- }
- boolean warnings = display.getWarnings ();
- display.setWarnings (false);
- if (index != count) {
- buffer = Converter.wcsToMbcs (getCodePage (), chars, true);
- }
- OS.XmTextReplace (textHandle, start [0], end [0], buffer);
- int position = start [0] + count;
- OS.XmTextSetInsertionPosition (textHandle, position);
- display.setWarnings (warnings);
- return false;
- }
- }
- return true;
-}
-boolean sendKeyEvent (int type, XKeyEvent xEvent) {
- Event event = new Event ();
- event.time = xEvent.time;
- if (!setKeyState (event, xEvent)) return true;
- Control control = this;
- if ((state & CANVAS) != 0) {
- if ((style & SWT.NO_FOCUS) != 0) {
- control = display.getFocusControl ();
- }
- }
- if (control != null) {
- control.sendEvent (type, event);
- // widget could be disposed at this point
-
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the key
- * events. If this happens, end the processing of
- * the key by returning false.
- */
- if (isDisposed ()) return false;
- }
- return event.doit;
-}
void sendMouseEvent (int type) {
int xDisplay = OS.XtDisplay (handle), xWindow = OS.XtWindow (handle);
int [] windowX = new int [1], windowY = new int [1], mask = new int [1], unused = new int [1];
@@ -3121,21 +3020,6 @@ int xFocusOut (XFocusChangeEvent xEvent) {
}
return 0;
}
-int XKeyPress (int w, int client_data, int call_data, int continue_to_dispatch) {
- XKeyEvent xEvent = new XKeyEvent ();
- OS.memmove (xEvent, call_data, XKeyEvent.sizeof);
- boolean doit = true;
- if (xEvent.keycode != 0) {
- doit = sendKeyEvent (SWT.KeyDown, xEvent);
- } else {
- doit = sendIMKeyEvent (SWT.KeyDown, xEvent);
- }
- if (!doit) {
- OS.memmove (continue_to_dispatch, new int [1], 4);
- return 1;
- }
- return 0;
-}
int XKeyRelease (int w, int client_data, int call_data, int continue_to_dispatch) {
XKeyEvent xEvent = new XKeyEvent ();
OS.memmove (xEvent, call_data, XKeyEvent.sizeof);
@@ -3147,11 +3031,7 @@ int XKeyRelease (int w, int client_data, int call_data, int continue_to_dispatch
showMenu (xEvent.x_root, xEvent.y_root);
}
}
- if (!sendKeyEvent (SWT.KeyUp, xEvent)) {
- OS.memmove (continue_to_dispatch, new int [1], 4);
- return 1;
- }
- return 0;
+ return super.XKeyRelease (w, client_data, call_data, continue_to_dispatch);
}
int XLeaveWindow (int w, int client_data, int call_data, int continue_to_dispatch) {
display.removeMouseHoverTimeOut ();
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Tracker.java
index 09e24b1b98..fe26955ae6 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Tracker.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Tracker.java
@@ -37,11 +37,12 @@ import org.eclipse.swt.events.*;
*/
public class Tracker extends Widget {
Composite parent;
- boolean tracking, stippled;
+ boolean tracking, cancelled, stippled;
Rectangle [] rectangles, proportions;
Rectangle bounds;
int cursorOrientation = SWT.NONE;
- int cursor;
+ int cursor, window, oldX, oldY;
+
final static int STEPSIZE_SMALL = 1;
final static int STEPSIZE_LARGE = 9;
@@ -152,8 +153,34 @@ public void addControlListener (ControlListener listener) {
addListener (SWT.Resize, typedListener);
addListener (SWT.Move, typedListener);
}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard, by sending
+ * it one of the messages defined in the <code>KeyListener</code>
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see KeyListener
+ * @see #removeKeyListener
+ */
+public void addKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener(SWT.KeyUp,typedListener);
+ addListener(SWT.KeyDown,typedListener);
+}
-Point adjustMoveCursor (int xDisplay, int xWindow) {
+Point adjustMoveCursor () {
final int unused[] = new int[1];
int actualX[] = new int[1];
int actualY[] = new int[1];
@@ -161,16 +188,17 @@ Point adjustMoveCursor (int xDisplay, int xWindow) {
int newX = bounds.x + bounds.width / 2;
int newY = bounds.y;
- OS.XWarpPointer (xDisplay, OS.None, xWindow, 0, 0, 0, 0, newX, newY);
+ int xDisplay = display.xDisplay;
+ OS.XWarpPointer (xDisplay, OS.None, window, 0, 0, 0, 0, newX, newY);
/*
* The call to XWarpPointer does not always place the pointer on the
* exact location that is specified, so do a query (below) to get the
* actual location of the pointer after it has been moved.
*/
- OS.XQueryPointer (xDisplay, xWindow, unused, unused, actualX, actualY, unused, unused, unused);
+ OS.XQueryPointer (xDisplay, window, unused, unused, actualX, actualY, unused, unused, unused);
return new Point (actualX[0], actualY[0]);
}
-Point adjustResizeCursor (int xDisplay, int xWindow) {
+Point adjustResizeCursor () {
int newX, newY;
if ((cursorOrientation & SWT.LEFT) != 0) {
@@ -192,13 +220,14 @@ Point adjustResizeCursor (int xDisplay, int xWindow) {
final int unused[] = new int[1];
int actualX[] = new int[1];
int actualY[] = new int[1];
- OS.XWarpPointer (xDisplay, 0, xWindow, 0, 0, 0, 0, newX, newY);
+ int xDisplay = display.xDisplay;
+ OS.XWarpPointer (xDisplay, 0, window, 0, 0, 0, 0, newX, newY);
/*
* The call to XWarpPointer does not always place the pointer on the
* exact location that is specified, so do a query (below) to get the
* actual location of the pointer after it has been moved.
*/
- OS.XQueryPointer (xDisplay, xWindow, unused, unused, actualX, actualY, unused, unused, unused);
+ OS.XQueryPointer (xDisplay, window, unused, unused, actualX, actualY, unused, unused, unused);
return new Point (actualX[0], actualY[0]);
}
static int checkStyle (int style) {
@@ -365,17 +394,17 @@ public boolean open () {
checkWidget ();
if (rectangles == null) return false;
int xDisplay = display.xDisplay;
- int xWindow = OS.XDefaultRootWindow (xDisplay);
+ window = OS.XDefaultRootWindow (xDisplay);
if (parent != null) {
- xWindow = OS.XtWindow (parent.handle);
- if (xWindow == 0) return false;
+ window = OS.XtWindow (parent.handle);
+ if (window == 0) return false;
}
- boolean cancelled = false;
+ cancelled = false;
tracking = true;
drawRectangles (rectangles, stippled);
int [] oldX = new int [1], oldY = new int [1];
int [] unused = new int [1], mask = new int [1];
- OS.XQueryPointer (xDisplay, xWindow, unused, unused, oldX, oldY, unused, unused, mask);
+ OS.XQueryPointer (xDisplay, window, unused, unused, oldX, oldY, unused, unused, mask);
/*
* If exactly one of UP/DOWN is specified as a style then set the cursor
@@ -395,288 +424,37 @@ public boolean open () {
boolean mouseDown = (mask [0] & mouseMasks) != 0;
if (!mouseDown) {
if ((style & SWT.RESIZE) != 0) {
- cursorPos = adjustResizeCursor (xDisplay, xWindow);
+ cursorPos = adjustResizeCursor ();
} else {
- cursorPos = adjustMoveCursor (xDisplay, xWindow);
+ cursorPos = adjustMoveCursor ();
}
oldX [0] = cursorPos.x; oldY [0] = cursorPos.y;
}
+ this.oldX = oldX [0];
+ this.oldY = oldY [0];
- int xEvent = OS.XtMalloc (XEvent.sizeof);
- XEvent anyEvent = new XEvent();
- int [] newX = new int [1], newY = new int [1];
- int xtContext = OS.XtDisplayToApplicationContext (xDisplay);
-
- int ptrGrabResult = OS.XGrabPointer (
- xDisplay,
- xWindow,
- 0,
+ int ptrGrabResult = OS.XGrabPointer (xDisplay, window, 0,
OS.ButtonPressMask | OS.ButtonReleaseMask | OS.PointerMotionMask,
- OS.GrabModeAsync,
- OS.GrabModeAsync,
- OS.None,
- OS.None,
- OS.CurrentTime);
- int kbdGrabResult = OS.XGrabKeyboard (
- xDisplay,
- xWindow,
- 0,
- OS.GrabModeAsync,
- OS.GrabModeAsync,
- OS.CurrentTime);
+ OS.GrabModeAsync, OS.GrabModeAsync, OS.None, OS.None, OS.CurrentTime);
+ int kbdGrabResult = OS.XGrabKeyboard (xDisplay, window, 0,
+ OS.GrabModeAsync, OS.GrabModeAsync, OS.CurrentTime);
- /*
- * Tracker behaves like a Dialog with its own OS event loop.
- */
+ /* Tracker behaves like a Dialog with its own OS event loop. */
+ XAnyEvent anyEvent = new XAnyEvent();
+ int xEvent = OS.XtMalloc (XEvent.sizeof);
+ int dispatch = OS.XtMalloc (4);
+ int xtContext = OS.XtDisplayToApplicationContext (xDisplay);
while (tracking) {
if (parent != null && parent.isDisposed ()) break;
OS.XtAppNextEvent (xtContext, xEvent);
- OS.memmove (anyEvent, xEvent, XEvent.sizeof);
+ OS.memmove (anyEvent, xEvent, XAnyEvent.sizeof);
+ int widget = OS.XtWindowToWidget (anyEvent.display, anyEvent.window);
switch (anyEvent.type) {
- case OS.MotionNotify:
- if (cursor != 0) {
- OS.XChangeActivePointerGrab (
- xDisplay,
- OS.ButtonPressMask | OS.ButtonReleaseMask | OS.PointerMotionMask,
- cursor,
- OS.CurrentTime);
- }
- // fall through
- case OS.ButtonRelease:
- OS.XQueryPointer (xDisplay, xWindow, unused, unused, newX, newY, unused, unused, unused);
- if (oldX [0] != newX [0] || oldY [0] != newY [0]) {
- Rectangle [] oldRectangles = rectangles;
- boolean oldStippled = stippled;
- Rectangle [] rectsToErase = new Rectangle [rectangles.length];
- for (int i = 0; i < rectangles.length; i++) {
- Rectangle current = rectangles [i];
- rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
- }
- Event event = new Event ();
- event.x = newX [0];
- event.y = newY [0];
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (newX [0] - oldX [0], newY [0] - oldY [0]);
- sendEvent (SWT.Resize, event);
- /*
- * It is possible (but unlikely) that application code
- * could have disposed the widget in the resize event.
- * If this happens then return false to indicate that
- * the move failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the resize event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- cursorPos = adjustResizeCursor (xDisplay, xWindow);
- newX [0] = cursorPos.x; newY [0] = cursorPos.y;
- } else {
- moveRectangles (newX [0] - oldX [0], newY [0] - oldY [0]);
- sendEvent (SWT.Move, event);
- /*
- * It is possible (but unlikely) that application code
- * could have disposed the widget in the move event.
- * If this happens then return false to indicate that
- * the move failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the move event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- }
- oldX [0] = newX [0]; oldY [0] = newY [0];
- }
- tracking = anyEvent.type != OS.ButtonRelease;
- break;
- case OS.KeyPress:
- XKeyEvent keyEvent = new XKeyEvent ();
- OS.memmove (keyEvent, xEvent, XKeyEvent.sizeof);
- if (keyEvent.keycode != 0) {
- int [] keysym = new int [1];
- OS.XLookupString (keyEvent, null, 0, keysym, null);
- keysym [0] &= 0xFFFF;
- int xChange = 0, yChange = 0;
- int stepSize = ((keyEvent.state & OS.ControlMask) != 0) ? STEPSIZE_SMALL : STEPSIZE_LARGE;
- switch (keysym [0]) {
- case OS.XK_KP_Enter:
- case OS.XK_Return:
- tracking = false;
- /*
- * Eat the subsequent KeyRelease event
- */
- OS.XtAppNextEvent (xtContext, xEvent);
- break;
- case OS.XK_Escape:
- tracking = false;
- cancelled = true;
- /*
- * Eat the subsequent KeyRelease event
- */
- OS.XtAppNextEvent (xtContext, xEvent);
- break;
- case OS.XK_Left:
- xChange = -stepSize;
- break;
- case OS.XK_Right:
- xChange = stepSize;
- break;
- case OS.XK_Up:
- yChange = -stepSize;
- break;
- case OS.XK_Down:
- yChange = stepSize;
- break;
- }
- if (xChange != 0 || yChange != 0) {
- Rectangle [] oldRectangles = rectangles;
- boolean oldStippled = stippled;
- Rectangle [] rectsToErase = new Rectangle [rectangles.length];
- for (int i = 0; i < rectangles.length; i++) {
- Rectangle current = rectangles [i];
- rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
- }
- Event event = new Event ();
- event.x = oldX [0] + xChange;
- event.y = oldY [0] + yChange;
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (xChange, yChange);
- sendEvent (SWT.Resize, event);
- /*
- * It is possible (but unlikely) that application code
- * could have disposed the widget in the resize event.
- * If this happens then return false to indicate that
- * the move failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the resize event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- cursorPos = adjustResizeCursor (xDisplay, xWindow);
- } else {
- moveRectangles (xChange, yChange);
- sendEvent (SWT.Move, event);
- /*
- * It is possible (but unlikely) that application code
- * could have disposed the widget in the move event.
- * If this happens then return false to indicate that
- * the move failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the move event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- cursorPos = adjustMoveCursor (xDisplay, xWindow);
- }
- oldX [0] = cursorPos.x; oldY [0] = cursorPos.y;
- }
- }
- break;
+ case OS.MotionNotify: XPointerMotion (widget, 0, xEvent, dispatch); break;
+ case OS.ButtonRelease: XButtonRelease (widget, 0, xEvent, dispatch); break;
+ case OS.KeyPress: XKeyPress (widget, 0, xEvent, dispatch); break;
+ case OS.KeyRelease: XKeyRelease (widget, 0, xEvent, dispatch); break;
case OS.ButtonPress:
- case OS.KeyRelease:
case OS.EnterNotify:
case OS.LeaveNotify:
/* Do not dispatch these */
@@ -685,10 +463,12 @@ public boolean open () {
OS.XtDispatchEvent (xEvent);
}
}
- OS.XtFree (xEvent);
+ if (xEvent != 0) OS.XtFree (xEvent);
+ if (dispatch != 0) OS.XtFree (dispatch);
if (!isDisposed()) drawRectangles (rectangles, stippled);
if (ptrGrabResult == OS.GrabSuccess) OS.XUngrabPointer (xDisplay, OS.CurrentTime);
if (kbdGrabResult == OS.GrabSuccess) OS.XUngrabKeyboard (xDisplay, OS.CurrentTime);
+ window = 0;
return !cancelled;
}
/**
@@ -715,6 +495,30 @@ public void removeControlListener (ControlListener listener) {
eventTable.unhook (SWT.Resize, listener);
eventTable.unhook (SWT.Move, listener);
}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see KeyListener
+ * @see #addKeyListener
+ */
+public void removeKeyListener(KeyListener listener) {
+ checkWidget();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook(SWT.KeyUp, listener);
+ eventTable.unhook(SWT.KeyDown, listener);
+}
void resizeRectangles (int xChange, int yChange) {
/*
* If the cursor orientation has not been set in the orientation of
@@ -879,4 +683,260 @@ public void setStippled (boolean stippled) {
checkWidget ();
this.stippled = stippled;
}
+
+int XButtonRelease (int w, int client_data, int call_data, int continue_to_dispatch) {
+ return xMouse (OS.ButtonRelease, w, client_data, call_data, continue_to_dispatch);
+}
+
+int XKeyPress (int w, int client_data, int call_data, int continue_to_dispatch) {
+ int result = super.XKeyPress (w, client_data, call_data, continue_to_dispatch);
+ if (result != 0) return result;
+ XKeyEvent keyEvent = new XKeyEvent ();
+ OS.memmove (keyEvent, call_data, XKeyEvent.sizeof);
+ if (keyEvent.keycode != 0) {
+ int [] keysym = new int [1];
+ OS.XLookupString (keyEvent, null, 0, keysym, null);
+ keysym [0] &= 0xFFFF;
+ int xChange = 0, yChange = 0;
+ int stepSize = ((keyEvent.state & OS.ControlMask) != 0) ? STEPSIZE_SMALL : STEPSIZE_LARGE;
+ switch (keysym [0]) {
+ case OS.XK_KP_Enter:
+ case OS.XK_Return:
+ tracking = false;
+ /* Eat the subsequent KeyRelease event */
+ OS.XtAppNextEvent (OS.XtDisplayToApplicationContext (keyEvent.display), call_data);
+ break;
+ case OS.XK_Escape:
+ tracking = false;
+ cancelled = true;
+ /* Eat the subsequent KeyRelease event */
+ OS.XtAppNextEvent (OS.XtDisplayToApplicationContext (keyEvent.display), call_data);
+ break;
+ case OS.XK_Left:
+ xChange = -stepSize;
+ break;
+ case OS.XK_Right:
+ xChange = stepSize;
+ break;
+ case OS.XK_Up:
+ yChange = -stepSize;
+ break;
+ case OS.XK_Down:
+ yChange = stepSize;
+ break;
+ }
+ if (xChange != 0 || yChange != 0) {
+ Rectangle [] oldRectangles = rectangles;
+ boolean oldStippled = stippled;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ event.x = oldX + xChange;
+ event.y = oldY + yChange;
+ Point cursorPos;
+ if ((style & SWT.RESIZE) != 0) {
+ resizeRectangles (xChange, yChange);
+ sendEvent (SWT.Resize, event);
+ /*
+ * It is possible (but unlikely) that application code
+ * could have disposed the widget in the resize event.
+ * If this happens then return false to indicate that
+ * the move failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ cursorPos = adjustResizeCursor ();
+ } else {
+ moveRectangles (xChange, yChange);
+ sendEvent (SWT.Move, event);
+ /*
+ * It is possible (but unlikely) that application code
+ * could have disposed the widget in the move event.
+ * If this happens then return false to indicate that
+ * the move failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ cursorPos = adjustMoveCursor ();
+ }
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+ }
+ }
+ return result;
+}
+
+int XPointerMotion (int w, int client_data, int call_data, int continue_to_dispatch) {
+ if (cursor != 0) {
+ int xDisplay = display.xDisplay;
+ OS.XChangeActivePointerGrab (xDisplay,
+ OS.ButtonPressMask | OS.ButtonReleaseMask | OS.PointerMotionMask,
+ cursor, OS.CurrentTime);
+ }
+ return xMouse (OS.MotionNotify, w, client_data, call_data, continue_to_dispatch);
+}
+
+int xMouse (int type, int w, int client_data, int call_data, int continue_to_dispatch) {
+ int xDisplay = display.xDisplay;
+ int [] newX = new int [1], newY = new int [1], unused = new int [1];
+ OS.XQueryPointer (xDisplay, window, unused, unused, newX, newY, unused, unused, unused);
+ if (oldX != newX [0] || oldY != newY [0]) {
+ Rectangle [] oldRectangles = rectangles;
+ boolean oldStippled = stippled;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ event.x = newX [0];
+ event.y = newY [0];
+ if ((style & SWT.RESIZE) != 0) {
+ resizeRectangles (newX [0] - oldX, newY [0] - oldY);
+ sendEvent (SWT.Resize, event);
+ /*
+ * It is possible (but unlikely) that application code
+ * could have disposed the widget in the resize event.
+ * If this happens then return false to indicate that
+ * the move failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ Point cursorPos = adjustResizeCursor ();
+ newX [0] = cursorPos.x;
+ newY [0] = cursorPos.y;
+ } else {
+ moveRectangles (newX [0] - oldX, newY [0] - oldY);
+ sendEvent (SWT.Move, event);
+ /*
+ * It is possible (but unlikely) that application code
+ * could have disposed the widget in the move event.
+ * If this happens then return false to indicate that
+ * the move failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return 1;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ }
+ oldX = newX [0];
+ oldY = newY [0];
+ }
+ tracking = type != OS.ButtonRelease;
+ return 0;
}
+
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Widget.java
index 0fae8e6fea..5d0134ccbf 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/motif/org/eclipse/swt/widgets/Widget.java
@@ -353,6 +353,9 @@ char fixMnemonic (char [] buffer) {
int focusProc (int w, int client_data, int call_data, int continue_to_dispatch) {
return 0;
}
+String getCodePage () {
+ return null;
+}
/**
* Returns the application defined widget data associated
* with the receiver, or null if it has not been set. The
@@ -754,6 +757,106 @@ void sendEvent (int eventType, Event event, boolean send) {
display.postEvent (event);
}
}
+boolean sendIMKeyEvent (int type, XKeyEvent xEvent) {
+ return sendIMKeyEvent (type, xEvent, 0);
+}
+boolean sendIMKeyEvent (int type, XKeyEvent xEvent, int textHandle) {
+ /*
+ * Bug in Motif. On Linux only, XmImMbLookupString () does not return
+ * XBufferOverflow as the status if the buffer is too small. The fix
+ * is to pass a large buffer.
+ */
+ byte [] buffer = new byte [512];
+ int [] status = new int [1], unused = new int [1];
+ int focusHandle = OS.XtWindowToWidget (xEvent.display, xEvent.window);
+ int length = OS.XmImMbLookupString (focusHandle, xEvent, buffer, buffer.length, unused, status);
+ if (status [0] == OS.XBufferOverflow) {
+ buffer = new byte [length];
+ length = OS.XmImMbLookupString (focusHandle, xEvent, buffer, length, unused, status);
+ }
+ if (length == 0) return true;
+
+ /* Convert from MBCS to UNICODE and send the event */
+ /* Use the character encoding for the default locale */
+ char [] chars = Converter.mbcsToWcs (null, buffer);
+ int index = 0, count = 0;
+ while (index < chars.length) {
+ if (chars [index] == 0) {
+ chars [count] = 0;
+ break;
+ }
+ Event event = new Event ();
+ event.time = xEvent.time;
+ event.character = chars [index];
+ setInputState (event, xEvent.state);
+ sendEvent (type, event);
+ // widget could be disposed at this point
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the key
+ * events. If this happens, end the processing of
+ * the key by returning false.
+ */
+ if (isDisposed ()) return false;
+ if (event.doit) chars [count++] = chars [index];
+ index++;
+ }
+ if (count == 0) return false;
+ if (textHandle != 0) {
+ /*
+ * Bug in Motif. On Solaris and Linux, XmImMbLookupString() clears
+ * the characters from the IME. This causes the characters to be
+ * stolen from the text widget. The fix is to detect that the IME
+ * has been cleared and use XmTextInsert() to insert the stolen
+ * characters. This problem does not happen on AIX.
+ */
+ byte [] testBuffer = new byte [5];
+ int testLength = OS.XmImMbLookupString (textHandle, xEvent, testBuffer, testBuffer.length, unused, unused);
+ if (testLength == 0 || index != count) {
+ int [] start = new int [1], end = new int [1];
+ OS.XmTextGetSelectionPosition (textHandle, start, end);
+ if (start [0] == end [0]) {
+ start [0] = end [0] = OS.XmTextGetInsertionPosition (textHandle);
+ }
+ boolean warnings = display.getWarnings ();
+ display.setWarnings (false);
+ if (index != count) {
+ buffer = Converter.wcsToMbcs (getCodePage (), chars, true);
+ }
+ OS.XmTextReplace (textHandle, start [0], end [0], buffer);
+ int position = start [0] + count;
+ OS.XmTextSetInsertionPosition (textHandle, position);
+ display.setWarnings (warnings);
+ return false;
+ }
+ }
+ return true;
+}
+boolean sendKeyEvent (int type, XKeyEvent xEvent) {
+ Event event = new Event ();
+ event.time = xEvent.time;
+ if (!setKeyState (event, xEvent)) return true;
+ Widget control = this;
+ if ((state & CANVAS) != 0) {
+ if ((style & SWT.NO_FOCUS) != 0) {
+ control = display.getFocusControl ();
+ }
+ }
+ if (control != null) {
+ control.sendEvent (type, event);
+ // widget could be disposed at this point
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the key
+ * events. If this happens, end the processing of
+ * the key by returning false.
+ */
+ if (isDisposed ()) return false;
+ }
+ return event.doit;
+}
/**
* Sets the application defined widget data associated
* with the receiver to be the argument. The <em>widget
@@ -961,9 +1064,27 @@ int XFocusChange (int w, int client_data, int call_data, int continue_to_dispatc
return 0;
}
int XKeyPress (int w, int client_data, int call_data, int continue_to_dispatch) {
+ XKeyEvent xEvent = new XKeyEvent ();
+ OS.memmove (xEvent, call_data, XKeyEvent.sizeof);
+ boolean doit = true;
+ if (xEvent.keycode != 0) {
+ doit = sendKeyEvent (SWT.KeyDown, xEvent);
+ } else {
+ doit = sendIMKeyEvent (SWT.KeyDown, xEvent);
+ }
+ if (!doit) {
+ OS.memmove (continue_to_dispatch, new int [1], 4);
+ return 1;
+ }
return 0;
}
int XKeyRelease (int w, int client_data, int call_data, int continue_to_dispatch) {
+ XKeyEvent xEvent = new XKeyEvent ();
+ OS.memmove (xEvent, call_data, XKeyEvent.sizeof);
+ if (!sendKeyEvent (SWT.KeyUp, xEvent)) {
+ OS.memmove (continue_to_dispatch, new int [1], 4);
+ return 1;
+ }
return 0;
}
int XLeaveWindow (int w, int client_data, int call_data, int continue_to_dispatch) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java
index bda007b08c..201282607d 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java
@@ -3082,20 +3082,7 @@ LRESULT WM_ACTIVATE (int wParam, int lParam) {
}
LRESULT WM_CHAR (int wParam, int lParam) {
- /*
- * Do not report a lead byte as a key pressed.
- */
- if (!OS.IsUnicode && OS.IsDBLocale) {
- byte lead = (byte) (wParam & 0xFF);
- if (OS.IsDBCSLeadByte (lead)) return null;
- }
- display.lastAscii = wParam;
- display.lastNull = wParam == 0;
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_CHAR, wParam, lParam)) {
- return LRESULT.ONE;
- }
- // widget could be disposed at this point
- return null;
+ return wmChar (handle, wParam, lParam);
}
LRESULT WM_CLEAR (int wParam, int lParam) {
@@ -3281,17 +3268,7 @@ LRESULT WM_HSCROLL (int wParam, int lParam) {
}
LRESULT WM_IME_CHAR (int wParam, int lParam) {
- Display display = this.display;
- display.lastKey = 0;
- display.lastAscii = wParam;
- display.lastVirtual = display.lastNull = display.lastDead = false;
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
- return LRESULT.ONE;
- }
- sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
- // widget could be disposed at this point
- display.lastKey = display.lastAscii = 0;
- return LRESULT.ONE;
+ return wmIMEChar (handle, wParam, lParam);
}
LRESULT WM_IME_COMPOSITION (int wParam, int lParam) {
@@ -3355,317 +3332,11 @@ LRESULT WM_INITMENUPOPUP (int wParam, int lParam) {
}
LRESULT WM_KEYDOWN (int wParam, int lParam) {
-
- /* Ignore repeating modifier keys by testing key down state */
- switch (wParam) {
- case OS.VK_SHIFT:
- case OS.VK_MENU:
- case OS.VK_CONTROL:
- case OS.VK_CAPITAL:
- case OS.VK_NUMLOCK:
- case OS.VK_SCROLL:
- if ((lParam & 0x40000000) != 0) return null;
- }
-
- /* Clear last key and last ascii because a new key has been typed */
- display.lastAscii = display.lastKey = 0;
- display.lastVirtual = display.lastNull = display.lastDead = false;
-
- /*
- * Do not report a lead byte as a key pressed.
- */
- if (!OS.IsUnicode && OS.IsDBLocale) {
- byte lead = (byte) (wParam & 0xFF);
- if (OS.IsDBCSLeadByte (lead)) return null;
- }
-
- /* Map the virtual key */
- /*
- * Bug in WinCE. MapVirtualKey() returns incorrect values.
- * The fix is to rely on a key mappings table to determine
- * whether the key event must be sent now or if a WM_CHAR
- * event will follow. The key mappings table maps virtual
- * keys to SWT key codes and does not contain mappings for
- * Windows virtual keys like VK_A. Virtual keys that are
- * both virtual and ASCII are a special case.
- */
- int mapKey = 0;
- if (OS.IsWinCE) {
- switch (wParam) {
- case OS.VK_BACK: mapKey = SWT.BS; break;
- case OS.VK_RETURN: mapKey = SWT.CR; break;
- case OS.VK_DELETE: mapKey = SWT.DEL; break;
- case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
- case OS.VK_TAB: mapKey = SWT.TAB; break;
- }
- } else {
- mapKey = OS.MapVirtualKey (wParam, 2);
- }
-
- /*
- * Bug in Windows 95 and NT. When the user types an accent key such
- * as ^ to get an accented character on a German keyboard, the accent
- * key should be ignored and the next key that the user types is the
- * accented key. The fix is to detect the accent key stroke (called
- * a dead key) by testing the high bit of the value returned by
- * MapVirtualKey(). A further problem is that the high bit on
- * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
- * They should both be bit 32.
- *
- * When the user types an accent key that does not correspond to a
- * virtual key, MapVirtualKey() won't set the high bit to indicate
- * a dead key. This happens when an accent key, such as '^' is the
- * result of a modifier such as Shift key and MapVirtualKey() always
- * returns the unshifted key. The fix is to peek for a WM_DEADCHAR
- * and avoid issuing the event.
- */
- if (OS.IsWinNT) {
- if ((mapKey & 0x80000000) != 0) return null;
- } else {
- if ((mapKey & 0x8000) != 0) return null;
- }
- MSG msg = new MSG ();
- int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
- if (OS.PeekMessage (msg, handle, OS.WM_DEADCHAR, OS.WM_DEADCHAR, flags)) {
- display.lastDead = true;
- display.lastVirtual = mapKey == 0;
- display.lastKey = display.lastVirtual ? wParam : mapKey;
- return null;
- }
-
- /*
- * If we are going to get a WM_CHAR, ensure that last key has
- * the correct character value for the key down and key up
- * events. It is not sufficient to ignore the WM_KEYDOWN
- * (when we know we are going to get a WM_CHAR) and compute
- * the key in WM_CHAR because there is not enough information
- * by the time we get the WM_CHAR. For example, when the user
- * types Ctrl+Shift+6 on a US keyboard, we get a WM_CHAR with
- * wParam=30. When the user types Ctrl+Shift+6 on a German
- * keyboard, we also get a WM_CHAR with wParam=30. On the US
- * keyboard Shift+6 is ^, on the German keyboard Shift+6 is &.
- * There is no way to map wParam=30 in WM_CHAR to the correct
- * value. Also, on international keyboards, the control key
- * may be down when the user has not entered a control character.
- *
- * NOTE: On Windows 98, keypad keys are virtual despite the
- * fact that a WM_CHAR is issued. On Windows 2000 and XP,
- * they are not virtual. Therefore it is necessary to force
- * numeric keypad keys to be virtual.
- */
- display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
- if (display.lastVirtual) {
- display.lastKey = wParam;
- /*
- * Feature in Windows. The virtual key VK_DELETE is not
- * treated as both a virtual key and an ASCII key by Windows.
- * Therefore, we will not receive a WM_CHAR for this key.
- * The fix is to treat VK_DELETE as a special case and map
- * the ASCII value explictly (Delete is 0x7F).
- */
- if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
-
- /*
- * It is possible to get a WM_CHAR for a virtual key when
- * Num Lock is on. If the user types Home while Num Lock
- * is down, a WM_CHAR is issued with WPARM=55 (for the
- * character 7). If we are going to get a WM_CHAR we need
- * to ensure that the last key has the correct value. Note
- * that Ctrl+Home does not issue a WM_CHAR when Num Lock is
- * down.
- */
- if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
- /*
- * Feature in Windows. Calling to ToAscii() or ToUnicode(), clears
- * the accented state such that the next WM_CHAR loses the accent.
- * This makes is critical that the accent key is detected. Also,
- * these functions clear the character that is entered using the
- * special Windows keypad sequence when NumLock is down (ie. typing
- * ALT+0231 should gives 'c' with a cedilla when NumLock is down).
- */
- if (display.asciiKey (display.lastKey) != 0) return null;
- display.lastAscii = display.numpadKey (display.lastKey);
- }
- } else {
- /*
- * Convert LastKey to lower case because Windows non-virtual
- * keys that are also ASCII keys, such as like VK_A, are have
- * upper case values in WM_KEYDOWN despite the fact that the
- * Shift was not pressed.
- */
- display.lastKey = OS.CharLower ((short) mapKey);
-
- /*
- * Feature in Windows. The virtual key VK_CANCEL is treated
- * as both a virtual key and ASCII key by Windows. This
- * means that a WM_CHAR with WPARAM=3 will be issued for
- * this key. In order to distinguish between this key and
- * Ctrl+C, mark the key as virtual.
- */
- if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
-
- /*
- * Some key combinations map to Windows ASCII keys depending
- * on the keyboard. For example, Ctrl+Alt+Q maps to @ on a
- * German keyboard. If the current key combination is special,
- * the correct character is placed in wParam for processing in
- * WM_CHAR. If this is the case, issue the key down event from
- * inside WM_CHAR.
- */
- int asciiKey = display.asciiKey (wParam);
- if (asciiKey != 0) {
- /*
- * When the user types Ctrl+Space, ToAscii () maps this to
- * Space. Normally, ToAscii () maps a key to a different
- * key if both a WM_KEYDOWN and a WM_CHAR will be issued.
- * To avoid the extra SWT.KeyDown, look for a space and
- * issue the event from WM_CHAR.
- */
- if (asciiKey == ' ') return null;
- if (asciiKey != wParam) return null;
- /*
- * Feature in Windows. The virtual key VK_CANCEL is treated
- * as both a virtual key and ASCII key by Windows. This
- * means that a WM_CHAR with WPARAM=3 will be issued for
- * this key. To avoid the extra SWT.KeyDown, look for
- * VK_CANCEL and issue the event from WM_CHAR.
- */
- if (wParam == OS.VK_CANCEL) return null;
- }
-
- /*
- * If the control key is not down at this point, then
- * the key that was pressed was an accent key or a regular
- * key such as 'A' or Shift+A. In that case, issue the
- * key event from WM_CHAR.
- */
- if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return null;
-
- /*
- * Get the shifted state or convert to lower case if necessary.
- * If the user types Ctrl+A, LastAscii should be 'a', not 'A'.
- * If the user types Ctrl+Shift+A, LastAscii should be 'A'.
- * If the user types Ctrl+Shift+6, the value of LastAscii will
- * depend on the international keyboard.
- */
- if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
- display.lastAscii = display.shiftedKey (wParam);
- if (display.lastAscii == 0) display.lastAscii = mapKey;
- } else {
- display.lastAscii = OS.CharLower ((short) mapKey);
- }
-
- /* Note that Ctrl+'@' is ASCII NUL and is delivered in WM_CHAR */
- if (display.lastAscii == '@') return null;
- display.lastAscii = display.controlKey (display.lastAscii);
- }
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_KEYDOWN, wParam, lParam)) {
- return LRESULT.ONE;
- }
- // widget could be disposed at this point
- return null;
+ return wmKeyDown (handle, wParam, lParam);
}
LRESULT WM_KEYUP (int wParam, int lParam) {
- Display display = this.display;
-
- /* Check for hardware keys */
- if (OS.IsWinCE) {
- if (OS.VK_APP1 <= wParam && wParam <= OS.VK_APP6) {
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = display.lastDead = false;
- Event event = new Event ();
- event.detail = wParam - OS.VK_APP1 + 1;
- /* Check the bit 30 to get the key state */
- int type = (lParam & 0x40000000) != 0 ? SWT.HardKeyUp : SWT.HardKeyDown;
- if (setInputState (event, type)) sendEvent (type, event);
- // widget could be disposed at this point
- return null;
- }
- }
-
- /*
- * If the key up is not hooked, reset last key
- * and last ascii in case the key down is hooked.
- */
- if (!hooks (SWT.KeyUp) && !display.filters (SWT.KeyUp)) {
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = display.lastDead = false;
- return null;
- }
-
- /* Map the virtual key. */
- /*
- * Bug in WinCE. MapVirtualKey() returns incorrect values.
- * The fix is to rely on a key mappings table to determine
- * whether the key event must be sent now or if a WM_CHAR
- * event will follow. The key mappings table maps virtual
- * keys to SWT key codes and does not contain mappings for
- * Windows virtual keys like VK_A. Virtual keys that are
- * both virtual and ASCII are a special case.
- */
- int mapKey = 0;
- if (OS.IsWinCE) {
- switch (wParam) {
- case OS.VK_BACK: mapKey = SWT.BS; break;
- case OS.VK_RETURN: mapKey = SWT.CR; break;
- case OS.VK_DELETE: mapKey = SWT.DEL; break;
- case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
- case OS.VK_TAB: mapKey = SWT.TAB; break;
- }
- } else {
- mapKey = OS.MapVirtualKey (wParam, 2);
- }
-
- /*
- * Bug in Windows 95 and NT. When the user types an accent key such
- * as ^ to get an accented character on a German keyboard, the accent
- * key should be ignored and the next key that the user types is the
- * accented key. The fix is to detect the accent key stroke (called
- * a dead key) by testing the high bit of the value returned by
- * MapVirtualKey (). A further problem is that the high bit on
- * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
- * They should both be bit 32.
- */
- if (OS.IsWinNT) {
- if ((mapKey & 0x80000000) != 0) return null;
- } else {
- if ((mapKey & 0x8000) != 0) return null;
- }
- if (display.lastDead) return null;
-
- /*
- * NOTE: On Windows 98, keypad keys are virtual despite the
- * fact that a WM_CHAR is issued. On Windows 2000 and XP,
- * they are not virtual. Therefore it is necessary to force
- * numeric keypad keys to be virtual.
- */
- display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
- if (display.lastVirtual) {
- display.lastKey = wParam;
- } else {
- /*
- * Feature in Windows. The virtual key VK_CANCEL is treated
- * as both a virtual key and ASCII key by Windows. This
- * means that a WM_CHAR with WPARAM=3 will be issued for
- * this key. In order to distingush between this key and
- * Ctrl+C, mark the key as virtual.
- */
- if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
- if (display.lastKey == 0) {
- display.lastAscii = 0;
- display.lastNull = display.lastDead = false;
- return null;
- }
- }
- LRESULT result = null;
- if (!sendKeyEvent (SWT.KeyUp, OS.WM_KEYUP, wParam, lParam)) {
- result = LRESULT.ONE;
- }
- // widget could be disposed at this point
- display.lastKey = display.lastAscii = 0;
- display.lastVirtual = display.lastNull = display.lastDead = false;
- return result;
+ return wmKeyUp (handle, wParam, lParam);
}
LRESULT WM_KILLFOCUS (int wParam, int lParam) {
@@ -4237,27 +3908,7 @@ LRESULT WM_SIZE (int wParam, int lParam) {
}
LRESULT WM_SYSCHAR (int wParam, int lParam) {
- Display display = this.display;
- display.lastAscii = wParam;
- display.lastNull = wParam == 0;
-
- /* Do not issue a key down if a menu bar mnemonic was invoked */
- if (!hooks (SWT.KeyDown) && !display.filters (SWT.KeyDown)) {
- return null;
- }
-
- /* Call the window proc to determine whether it is a system key or mnemonic */
- boolean oldKeyHit = display.mnemonicKeyHit;
- display.mnemonicKeyHit = true;
- int result = callWindowProc (OS.WM_SYSCHAR, wParam, lParam);
- boolean consumed = false;
- if (!display.mnemonicKeyHit) {
- consumed = !sendKeyEvent (SWT.KeyDown, OS.WM_SYSCHAR, wParam, lParam);
- // widget could be disposed at this point
- }
- consumed |= display.mnemonicKeyHit;
- display.mnemonicKeyHit = oldKeyHit;
- return consumed ? LRESULT.ONE : new LRESULT (result);
+ return wmSysChar (windowProc (), handle, wParam, lParam);
}
LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
@@ -4378,106 +4029,11 @@ LRESULT WM_SYSCOMMAND (int wParam, int lParam) {
}
LRESULT WM_SYSKEYDOWN (int wParam, int lParam) {
- /*
- * Feature in Windows. When WM_SYSKEYDOWN is sent,
- * the user pressed ALT+<key> or F10 to get to the
- * menu bar. In order to issue events for F10 but
- * ignore other key presses when the ALT is not down,
- * make sure that either F10 was pressed or that ALT
- * is pressed.
- */
- if (wParam != OS.VK_F10) {
- /* Make sure WM_SYSKEYDOWN was sent by ALT-<aKey>. */
- if ((lParam & 0x20000000) == 0) return null;
- }
-
- /* Ignore well known system keys */
- switch (wParam) {
- case OS.VK_F4: return null;
- }
-
- /* Ignore repeating modifier keys by testing key down state */
- switch (wParam) {
- case OS.VK_SHIFT:
- case OS.VK_MENU:
- case OS.VK_CONTROL:
- case OS.VK_CAPITAL:
- case OS.VK_NUMLOCK:
- case OS.VK_SCROLL:
- if ((lParam & 0x40000000) != 0) return null;
- }
-
- /* Clear last key and last ascii because a new key has been typed */
- display.lastAscii = display.lastKey = 0;
- display.lastVirtual = display.lastNull = display.lastDead = false;
-
- /* If are going to get a WM_SYSCHAR, ignore this message. */
- /*
- * Bug in WinCE. MapVirtualKey() returns incorrect values.
- * The fix is to rely on a key mappings table to determine
- * whether the key event must be sent now or if a WM_CHAR
- * event will follow. The key mappings table maps virtual
- * keys to SWT key codes and does not contain mappings for
- * Windows virtual keys like VK_A. Virtual keys that are
- * both virtual and ASCII are a special case.
- */
- int mapKey = 0;
- if (OS.IsWinCE) {
- switch (wParam) {
- case OS.VK_BACK: mapKey = SWT.BS; break;
- case OS.VK_RETURN: mapKey = SWT.CR; break;
- case OS.VK_DELETE: mapKey = SWT.DEL; break;
- case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
- case OS.VK_TAB: mapKey = SWT.TAB; break;
- }
- } else {
- mapKey = OS.MapVirtualKey (wParam, 2);
- }
- display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
- if (display.lastVirtual) {
- display.lastKey = wParam;
- /*
- * Feature in Windows. The virtual key VK_DELETE is not
- * treated as both a virtual key and an ASCII key by Windows.
- * Therefore, we will not receive a WM_SYSCHAR for this key.
- * The fix is to treat VK_DELETE as a special case and map
- * the ASCII value explictly (Delete is 0x7F).
- */
- if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
-
- /* When a keypad key is typed, a WM_SYSCHAR is not issued */
- if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
- display.lastAscii = display.numpadKey (display.lastKey);
- }
- } else {
- /*
- * Convert LastKey to lower case because Windows non-virtual
- * keys that are also ASCII keys, such as like VK_A, are have
- * upper case values in WM_SYSKEYDOWN despite the fact that the
- * Shift was not pressed.
- */
- display.lastKey = OS.CharLower ((short) mapKey);
-
- /*
- * Feature in Windows 98. MapVirtualKey() indicates that
- * a WM_SYSCHAR message will occur for Alt+Enter but
- * this message never happens. The fix is to issue the
- * event from WM_SYSKEYDOWN and map VK_RETURN to '\r'.
- */
- if (OS.IsWinNT) return null;
- if (wParam != OS.VK_RETURN) return null;
- display.lastAscii = '\r';
- }
-
- if (!sendKeyEvent (SWT.KeyDown, OS.WM_SYSKEYDOWN, wParam, lParam)) {
- return LRESULT.ONE;
- }
- // widget could be disposed at this point
- return null;
+ return wmSysKeyDown (handle, wParam, lParam);
}
LRESULT WM_SYSKEYUP (int wParam, int lParam) {
- return WM_KEYUP (wParam, lParam);
+ return wmSysKeyUp (handle, wParam, lParam);
}
LRESULT WM_TIMER (int wParam, int lParam) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java
index 22e5c51239..59797f28e0 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tracker.java
@@ -38,11 +38,12 @@ import org.eclipse.swt.events.*;
*/
public class Tracker extends Widget {
Control parent;
- boolean tracking, stippled;
+ boolean tracking, cancelled, stippled;
Rectangle [] rectangles, proportions;
Rectangle bounds;
int resizeCursor, clientCursor, cursorOrientation = SWT.NONE;
boolean inEvent = false;
+ int oldProc, oldX, oldY;
/*
* The following values mirror step sizes on Windows
@@ -158,6 +159,33 @@ public void addControlListener (ControlListener listener) {
addListener (SWT.Move, typedListener);
}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard, by sending
+ * it one of the messages defined in the <code>KeyListener</code>
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see KeyListener
+ * @see #removeKeyListener
+ */
+public void addKeyListener (KeyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ TypedListener typedListener = new TypedListener (listener);
+ addListener (SWT.KeyUp,typedListener);
+ addListener (SWT.KeyDown,typedListener);
+}
+
Point adjustMoveCursor () {
int newX = bounds.x + bounds.width / 2;
int newY = bounds.y;
@@ -413,11 +441,8 @@ void moveRectangles (int xChange, int yChange) {
public boolean open () {
checkWidget ();
if (rectangles == null) return false;
- boolean cancelled = false;
+ cancelled = false;
tracking = true;
- Event event = new Event ();
- MSG msg = new MSG ();
- boolean isMirrored = parent != null && (parent.style & SWT.MIRRORED) != 0;
/*
* If exactly one of UP/DOWN is specified as a style then set the cursor
@@ -455,36 +480,8 @@ public boolean open () {
0,
OS.GetModuleHandle (null),
null);
- final int oldProc = OS.GetWindowLong (hwndTransparent, OS.GWL_WNDPROC);
- Object windowProc = new Object () {
- public int windowProc (int hwnd, int msg, int wParam, int lParam) {
- switch (msg) {
- /*
- * We typically do not want to answer that the transparent window is
- * transparent to hits since doing so negates the effect of having it
- * to grab events. However, clients of the tracker should not be aware
- * of this transparent window. Therefore if there is a hit query
- * performed as a result of client code then answer that the transparent
- * window is transparent to hits so that its existence will not impact
- * the client.
- */
- case OS.WM_NCHITTEST:
- if (inEvent) return OS.HTTRANSPARENT;
- break;
- case OS.WM_SETCURSOR:
- if (clientCursor != 0) {
- OS.SetCursor (clientCursor);
- return 1;
- }
- if (resizeCursor != 0) {
- OS.SetCursor (resizeCursor);
- return 1;
- }
- }
- return OS.CallWindowProc (oldProc, hwnd, msg, wParam, lParam);
- }
- };
- newProc = new Callback (windowProc, "windowProc", 4); //$NON-NLS-1$
+ oldProc = OS.GetWindowLong (hwndTransparent, OS.GWL_WNDPROC);
+ newProc = new Callback (this, "transparentProc", 4); //$NON-NLS-1$
OS.SetWindowLong (hwndTransparent, OS.GWL_WNDPROC, newProc.getAddress ());
}
@@ -501,255 +498,28 @@ public boolean open () {
cursorPos = adjustMoveCursor ();
}
}
-
- int oldX = cursorPos.x, oldY = cursorPos.y;
- /*
- * Tracker behaves like a Dialog with its own OS event loop.
- */
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+
+ /* Tracker behaves like a Dialog with its own OS event loop. */
+ MSG msg = new MSG ();
while (tracking && !cancelled) {
if (parent != null && parent.isDisposed ()) break;
OS.GetMessage (msg, 0, 0, 0);
+ OS.TranslateMessage (msg);
int message = msg.message;
switch (message) {
case OS.WM_LBUTTONUP:
case OS.WM_MOUSEMOVE:
- int newPos = OS.GetMessagePos ();
- int newX = (short) (newPos & 0xFFFF);
- int newY = (short) (newPos >> 16);
- if (newX != oldX || newY != oldY) {
- Rectangle [] oldRectangles = rectangles;
- boolean oldStippled = stippled;
- Rectangle [] rectsToErase = new Rectangle [rectangles.length];
- for (int i = 0; i < rectangles.length; i++) {
- Rectangle current = rectangles [i];
- rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
- }
- event.x = newX;
- event.y = newY;
- if ((style & SWT.RESIZE) != 0) {
- if (isMirrored) {
- resizeRectangles (oldX - newX, newY - oldY);
- } else {
- resizeRectangles (newX - oldX, newY - oldY);
- }
- inEvent = true;
- sendEvent (SWT.Resize, event);
- inEvent = false;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the resize
- * event. If this happens, return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the resize event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- }
- else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- cursorPos = adjustResizeCursor ();
- newX = cursorPos.x; newY = cursorPos.y;
- } else {
- if (isMirrored) {
- moveRectangles (oldX - newX, newY - oldY);
- } else {
- moveRectangles (newX - oldX, newY - oldY);
- }
- inEvent = true;
- sendEvent (SWT.Move, event);
- inEvent = false;
- /*
- * It is possible (but unlikely), that application
- * code could have disposed the widget in the move
- * event. If this happens, return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the move event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- }
- oldX = newX; oldY = newY;
- }
- tracking = msg.message != OS.WM_LBUTTONUP;
- break;
- case OS.WM_SYSKEYDOWN:
- cancelled = true;
- tracking = false;
- break;
- case OS.WM_KEYDOWN:
- int stepSize = OS.GetKeyState (OS.VK_CONTROL) < 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE;
- int xChange = 0, yChange = 0;
- switch (msg.wParam) {
- case OS.VK_ESCAPE:
- cancelled = true;
- tracking = false;
- break;
- case OS.VK_RETURN:
- tracking = false;
- break;
- case OS.VK_LEFT:
- xChange = isMirrored ? stepSize : -stepSize;
- break;
- case OS.VK_RIGHT:
- xChange = isMirrored ? -stepSize : stepSize;
- break;
- case OS.VK_UP:
- yChange = -stepSize;
- break;
- case OS.VK_DOWN:
- yChange = stepSize;
- break;
- }
- if (xChange != 0 || yChange != 0) {
- Rectangle [] oldRectangles = rectangles;
- boolean oldStippled = stippled;
- Rectangle [] rectsToErase = new Rectangle [rectangles.length];
- for (int i = 0; i < rectangles.length; i++) {
- Rectangle current = rectangles [i];
- rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
- }
- event.x = oldX + xChange;
- event.y = oldY + yChange;
- if ((style & SWT.RESIZE) != 0) {
- resizeRectangles (xChange, yChange);
- inEvent = true;
- sendEvent (SWT.Resize, event);
- inEvent = false;
- /*
- * It is possible (but unlikely) that application
- * code could have disposed the widget in the resize
- * event. If this happens return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the resize event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- cursorPos = adjustResizeCursor ();
- } else {
- moveRectangles (xChange, yChange);
- inEvent = true;
- sendEvent (SWT.Move, event);
- inEvent = false;
- /*
- * It is possible (but unlikely) that application
- * code could have disposed the widget in the move
- * event. If this happens return false to indicate
- * that the tracking has failed.
- */
- if (isDisposed ()) {
- cancelled = true;
- break;
- }
- boolean draw = false;
- /*
- * It is possible that application code could have
- * changed the rectangles in the move event. If this
- * happens then only redraw the tracker if the rectangle
- * values have changed.
- */
- if (rectangles != oldRectangles) {
- int length = rectangles.length;
- if (length != rectsToErase.length) {
- draw = true;
- } else {
- for (int i = 0; i < length; i++) {
- if (!rectangles [i].equals (rectsToErase [i])) {
- draw = true;
- break;
- }
- }
- }
- } else {
- draw = true;
- }
- if (draw) {
- drawRectangles (rectsToErase, oldStippled);
- drawRectangles (rectangles, stippled);
- }
- cursorPos = adjustMoveCursor ();
- }
- oldX = cursorPos.x; oldY = cursorPos.y;
- }
+ wmMouse (message, msg.wParam, msg.lParam);
break;
+ case OS.WM_IME_CHAR: wmIMEChar (msg.hwnd, msg.wParam, msg.lParam); break;
+ case OS.WM_CHAR: wmChar (msg.hwnd, msg.wParam, msg.lParam); break;
+ case OS.WM_KEYDOWN: wmKeyDown (msg.hwnd, msg.wParam, msg.lParam); break;
+ case OS.WM_KEYUP: wmKeyUp (msg.hwnd, msg.wParam, msg.lParam); break;
+ case OS.WM_SYSCHAR: wmSysChar (0, msg.hwnd, msg.wParam, msg.lParam); break;
+ case OS.WM_SYSKEYDOWN: wmSysKeyDown (msg.hwnd, msg.wParam, msg.lParam); break;
+ case OS.WM_SYSKEYUP: wmSysKeyUp (msg.hwnd, msg.wParam, msg.lParam); break;
}
if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) continue;
if (OS.WM_MOUSEFIRST <= message && message <= OS.WM_MOUSELAST) continue;
@@ -766,6 +536,7 @@ public boolean open () {
}
if (newProc != null) {
newProc.dispose ();
+ oldProc = 0;
}
/*
* Cleanup: If this tracker was resizing then the last cursor that it created
@@ -773,6 +544,7 @@ public boolean open () {
*/
if (resizeCursor != 0) {
OS.DestroyCursor (resizeCursor);
+ resizeCursor = 0;
}
tracking = false;
return !cancelled;
@@ -803,6 +575,31 @@ public void removeControlListener (ControlListener listener) {
eventTable.unhook (SWT.Move, listener);
}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when keys are pressed and released on the system keyboard.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see KeyListener
+ * @see #addKeyListener
+ */
+public void removeKeyListener(KeyListener listener) {
+ checkWidget ();
+ if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+ if (eventTable == null) return;
+ eventTable.unhook (SWT.KeyUp, listener);
+ eventTable.unhook (SWT.KeyDown, listener);
+}
+
void resizeRectangles (int xChange, int yChange) {
/*
* If the cursor orientation has not been set in the orientation of
@@ -972,4 +769,287 @@ public void setStippled (boolean stippled) {
checkWidget ();
this.stippled = stippled;
}
+
+int transparentProc (int hwnd, int msg, int wParam, int lParam) {
+ switch (msg) {
+ /*
+ * We typically do not want to answer that the transparent window is
+ * transparent to hits since doing so negates the effect of having it
+ * to grab events. However, clients of the tracker should not be aware
+ * of this transparent window. Therefore if there is a hit query
+ * performed as a result of client code then answer that the transparent
+ * window is transparent to hits so that its existence will not impact
+ * the client.
+ */
+ case OS.WM_NCHITTEST:
+ if (inEvent) return OS.HTTRANSPARENT;
+ break;
+ case OS.WM_SETCURSOR:
+ if (clientCursor != 0) {
+ OS.SetCursor (clientCursor);
+ return 1;
+ }
+ if (resizeCursor != 0) {
+ OS.SetCursor (resizeCursor);
+ return 1;
+ }
+ }
+ return OS.CallWindowProc (oldProc, hwnd, msg, wParam, lParam);
+}
+
+LRESULT wmKeyDown (int hwnd, int wParam, int lParam) {
+ LRESULT result = super.wmKeyDown (hwnd, wParam, lParam);
+ if (result != null) return result;
+ boolean isMirrored = parent != null && (parent.style & SWT.MIRRORED) != 0;
+ int stepSize = OS.GetKeyState (OS.VK_CONTROL) < 0 ? STEPSIZE_SMALL : STEPSIZE_LARGE;
+ int xChange = 0, yChange = 0;
+ switch (wParam) {
+ case OS.VK_ESCAPE:
+ cancelled = true;
+ tracking = false;
+ break;
+ case OS.VK_RETURN:
+ tracking = false;
+ break;
+ case OS.VK_LEFT:
+ xChange = isMirrored ? stepSize : -stepSize;
+ break;
+ case OS.VK_RIGHT:
+ xChange = isMirrored ? -stepSize : stepSize;
+ break;
+ case OS.VK_UP:
+ yChange = -stepSize;
+ break;
+ case OS.VK_DOWN:
+ yChange = stepSize;
+ break;
+ }
+ if (xChange != 0 || yChange != 0) {
+ Rectangle [] oldRectangles = rectangles;
+ boolean oldStippled = stippled;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ event.x = oldX + xChange;
+ event.y = oldY + yChange;
+ Point cursorPos;
+ if ((style & SWT.RESIZE) != 0) {
+ resizeRectangles (xChange, yChange);
+ inEvent = true;
+ sendEvent (SWT.Resize, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely) that application
+ * code could have disposed the widget in the resize
+ * event. If this happens return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return LRESULT.ONE;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ cursorPos = adjustResizeCursor ();
+ } else {
+ moveRectangles (xChange, yChange);
+ inEvent = true;
+ sendEvent (SWT.Move, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely) that application
+ * code could have disposed the widget in the move
+ * event. If this happens return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return LRESULT.ONE;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ cursorPos = adjustMoveCursor ();
+ }
+ oldX = cursorPos.x;
+ oldY = cursorPos.y;
+ }
+ return result;
+}
+
+LRESULT wmSysKeyDown (int hwnd, int wParam, int lParam) {
+ LRESULT result = super.wmSysKeyDown (hwnd, wParam, lParam);
+ if (result != null) return result;
+ cancelled = true;
+ tracking = false;
+ return result;
+}
+
+LRESULT wmMouse (int message, int wParam, int lParam) {
+ boolean isMirrored = parent != null && (parent.style & SWT.MIRRORED) != 0;
+ int newPos = OS.GetMessagePos ();
+ int newX = (short) (newPos & 0xFFFF);
+ int newY = (short) (newPos >> 16);
+ if (newX != oldX || newY != oldY) {
+ Rectangle [] oldRectangles = rectangles;
+ boolean oldStippled = stippled;
+ Rectangle [] rectsToErase = new Rectangle [rectangles.length];
+ for (int i = 0; i < rectangles.length; i++) {
+ Rectangle current = rectangles [i];
+ rectsToErase [i] = new Rectangle (current.x, current.y, current.width, current.height);
+ }
+ Event event = new Event ();
+ event.x = newX;
+ event.y = newY;
+ if ((style & SWT.RESIZE) != 0) {
+ if (isMirrored) {
+ resizeRectangles (oldX - newX, newY - oldY);
+ } else {
+ resizeRectangles (newX - oldX, newY - oldY);
+ }
+ inEvent = true;
+ sendEvent (SWT.Resize, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the resize
+ * event. If this happens, return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return LRESULT.ONE;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the resize event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ Point cursorPos = adjustResizeCursor ();
+ newX = cursorPos.x; newY = cursorPos.y;
+ } else {
+ if (isMirrored) {
+ moveRectangles (oldX - newX, newY - oldY);
+ } else {
+ moveRectangles (newX - oldX, newY - oldY);
+ }
+ inEvent = true;
+ sendEvent (SWT.Move, event);
+ inEvent = false;
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the move
+ * event. If this happens, return false to indicate
+ * that the tracking has failed.
+ */
+ if (isDisposed ()) {
+ cancelled = true;
+ return LRESULT.ONE;
+ }
+ boolean draw = false;
+ /*
+ * It is possible that application code could have
+ * changed the rectangles in the move event. If this
+ * happens then only redraw the tracker if the rectangle
+ * values have changed.
+ */
+ if (rectangles != oldRectangles) {
+ int length = rectangles.length;
+ if (length != rectsToErase.length) {
+ draw = true;
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (!rectangles [i].equals (rectsToErase [i])) {
+ draw = true;
+ break;
+ }
+ }
+ }
+ } else {
+ draw = true;
+ }
+ if (draw) {
+ drawRectangles (rectsToErase, oldStippled);
+ drawRectangles (rectangles, stippled);
+ }
+ }
+ oldX = newX;
+ oldY = newY;
+ }
+ tracking = message != OS.WM_LBUTTONUP;
+ return null;
+}
+
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java
index 07e9c3604f..d055f75ea3 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Widget.java
@@ -166,6 +166,10 @@ public void addDisposeListener (DisposeListener listener) {
addListener (SWT.Dispose, typedListener);
}
+int callWindowProc (int msg, int wParam, int lParam) {
+ return 0;
+}
+
/**
* Returns a style with exactly one style bit set out of
* the specified set of exclusive style bits. All other
@@ -823,6 +827,26 @@ void sendEvent (int eventType, Event event, boolean send) {
}
}
+boolean sendKeyEvent (int type, int msg, int wParam, int lParam) {
+ Event event = new Event ();
+ if (!setKeyState (event, type, wParam, lParam)) return true;
+ return sendKeyEvent (type, msg, wParam, lParam, event);
+}
+
+boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
+ sendEvent (type, event);
+ // widget could be disposed at this point
+
+ /*
+ * It is possible (but unlikely), that application
+ * code could have disposed the widget in the key
+ * events. If this happens, end the processing of
+ * the key by returning false.
+ */
+ if (isDisposed ()) return false;
+ return event.doit;
+}
+
/**
* Sets the application defined widget data associated
* with the receiver to be the argument. The <em>widget
@@ -1058,4 +1082,477 @@ public String toString () {
}
return getName () + " {" + string + "}"; //$NON-NLS-1$ //$NON-NLS-2$
}
+
+LRESULT wmChar (int hwnd, int wParam, int lParam) {
+ /*
+ * Do not report a lead byte as a key pressed.
+ */
+ if (!OS.IsUnicode && OS.IsDBLocale) {
+ byte lead = (byte) (wParam & 0xFF);
+ if (OS.IsDBCSLeadByte (lead)) return null;
+ }
+ display.lastAscii = wParam;
+ display.lastNull = wParam == 0;
+ if (!sendKeyEvent (SWT.KeyDown, OS.WM_CHAR, wParam, lParam)) {
+ return LRESULT.ONE;
+ }
+ // widget could be disposed at this point
+ return null;
+}
+
+LRESULT wmIMEChar (int hwnd, int wParam, int lParam) {
+ Display display = this.display;
+ display.lastKey = 0;
+ display.lastAscii = wParam;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
+ return LRESULT.ONE;
+ }
+ sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
+ // widget could be disposed at this point
+ display.lastKey = display.lastAscii = 0;
+ return LRESULT.ONE;
+}
+
+LRESULT wmKeyDown (int hwnd, int wParam, int lParam) {
+
+ /* Ignore repeating modifier keys by testing key down state */
+ switch (wParam) {
+ case OS.VK_SHIFT:
+ case OS.VK_MENU:
+ case OS.VK_CONTROL:
+ case OS.VK_CAPITAL:
+ case OS.VK_NUMLOCK:
+ case OS.VK_SCROLL:
+ if ((lParam & 0x40000000) != 0) return null;
+ }
+
+ /* Clear last key and last ascii because a new key has been typed */
+ display.lastAscii = display.lastKey = 0;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+
+ /*
+ * Do not report a lead byte as a key pressed.
+ */
+ if (!OS.IsUnicode && OS.IsDBLocale) {
+ byte lead = (byte) (wParam & 0xFF);
+ if (OS.IsDBCSLeadByte (lead)) return null;
+ }
+
+ /* Map the virtual key */
+ /*
+ * Bug in WinCE. MapVirtualKey() returns incorrect values.
+ * The fix is to rely on a key mappings table to determine
+ * whether the key event must be sent now or if a WM_CHAR
+ * event will follow. The key mappings table maps virtual
+ * keys to SWT key codes and does not contain mappings for
+ * Windows virtual keys like VK_A. Virtual keys that are
+ * both virtual and ASCII are a special case.
+ */
+ int mapKey = 0;
+ if (OS.IsWinCE) {
+ switch (wParam) {
+ case OS.VK_BACK: mapKey = SWT.BS; break;
+ case OS.VK_RETURN: mapKey = SWT.CR; break;
+ case OS.VK_DELETE: mapKey = SWT.DEL; break;
+ case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
+ case OS.VK_TAB: mapKey = SWT.TAB; break;
+ }
+ } else {
+ mapKey = OS.MapVirtualKey (wParam, 2);
+ }
+
+ /*
+ * Bug in Windows 95 and NT. When the user types an accent key such
+ * as ^ to get an accented character on a German keyboard, the accent
+ * key should be ignored and the next key that the user types is the
+ * accented key. The fix is to detect the accent key stroke (called
+ * a dead key) by testing the high bit of the value returned by
+ * MapVirtualKey(). A further problem is that the high bit on
+ * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
+ * They should both be bit 32.
+ *
+ * When the user types an accent key that does not correspond to a
+ * virtual key, MapVirtualKey() won't set the high bit to indicate
+ * a dead key. This happens when an accent key, such as '^' is the
+ * result of a modifier such as Shift key and MapVirtualKey() always
+ * returns the unshifted key. The fix is to peek for a WM_DEADCHAR
+ * and avoid issuing the event.
+ */
+ if (OS.IsWinNT) {
+ if ((mapKey & 0x80000000) != 0) return null;
+ } else {
+ if ((mapKey & 0x8000) != 0) return null;
+ }
+ MSG msg = new MSG ();
+ int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
+ if (OS.PeekMessage (msg, hwnd, OS.WM_DEADCHAR, OS.WM_DEADCHAR, flags)) {
+ display.lastDead = true;
+ display.lastVirtual = mapKey == 0;
+ display.lastKey = display.lastVirtual ? wParam : mapKey;
+ return null;
+ }
+
+ /*
+ * If we are going to get a WM_CHAR, ensure that last key has
+ * the correct character value for the key down and key up
+ * events. It is not sufficient to ignore the WM_KEYDOWN
+ * (when we know we are going to get a WM_CHAR) and compute
+ * the key in WM_CHAR because there is not enough information
+ * by the time we get the WM_CHAR. For example, when the user
+ * types Ctrl+Shift+6 on a US keyboard, we get a WM_CHAR with
+ * wParam=30. When the user types Ctrl+Shift+6 on a German
+ * keyboard, we also get a WM_CHAR with wParam=30. On the US
+ * keyboard Shift+6 is ^, on the German keyboard Shift+6 is &.
+ * There is no way to map wParam=30 in WM_CHAR to the correct
+ * value. Also, on international keyboards, the control key
+ * may be down when the user has not entered a control character.
+ *
+ * NOTE: On Windows 98, keypad keys are virtual despite the
+ * fact that a WM_CHAR is issued. On Windows 2000 and XP,
+ * they are not virtual. Therefore it is necessary to force
+ * numeric keypad keys to be virtual.
+ */
+ display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
+ if (display.lastVirtual) {
+ display.lastKey = wParam;
+ /*
+ * Feature in Windows. The virtual key VK_DELETE is not
+ * treated as both a virtual key and an ASCII key by Windows.
+ * Therefore, we will not receive a WM_CHAR for this key.
+ * The fix is to treat VK_DELETE as a special case and map
+ * the ASCII value explictly (Delete is 0x7F).
+ */
+ if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
+
+ /*
+ * It is possible to get a WM_CHAR for a virtual key when
+ * Num Lock is on. If the user types Home while Num Lock
+ * is down, a WM_CHAR is issued with WPARM=55 (for the
+ * character 7). If we are going to get a WM_CHAR we need
+ * to ensure that the last key has the correct value. Note
+ * that Ctrl+Home does not issue a WM_CHAR when Num Lock is
+ * down.
+ */
+ if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
+ /*
+ * Feature in Windows. Calling to ToAscii() or ToUnicode(), clears
+ * the accented state such that the next WM_CHAR loses the accent.
+ * This makes is critical that the accent key is detected. Also,
+ * these functions clear the character that is entered using the
+ * special Windows keypad sequence when NumLock is down (ie. typing
+ * ALT+0231 should gives 'c' with a cedilla when NumLock is down).
+ */
+ if (display.asciiKey (display.lastKey) != 0) return null;
+ display.lastAscii = display.numpadKey (display.lastKey);
+ }
+ } else {
+ /*
+ * Convert LastKey to lower case because Windows non-virtual
+ * keys that are also ASCII keys, such as like VK_A, are have
+ * upper case values in WM_KEYDOWN despite the fact that the
+ * Shift was not pressed.
+ */
+ display.lastKey = OS.CharLower ((short) mapKey);
+
+ /*
+ * Feature in Windows. The virtual key VK_CANCEL is treated
+ * as both a virtual key and ASCII key by Windows. This
+ * means that a WM_CHAR with WPARAM=3 will be issued for
+ * this key. In order to distinguish between this key and
+ * Ctrl+C, mark the key as virtual.
+ */
+ if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
+
+ /*
+ * Some key combinations map to Windows ASCII keys depending
+ * on the keyboard. For example, Ctrl+Alt+Q maps to @ on a
+ * German keyboard. If the current key combination is special,
+ * the correct character is placed in wParam for processing in
+ * WM_CHAR. If this is the case, issue the key down event from
+ * inside WM_CHAR.
+ */
+ int asciiKey = display.asciiKey (wParam);
+ if (asciiKey != 0) {
+ /*
+ * When the user types Ctrl+Space, ToAscii () maps this to
+ * Space. Normally, ToAscii () maps a key to a different
+ * key if both a WM_KEYDOWN and a WM_CHAR will be issued.
+ * To avoid the extra SWT.KeyDown, look for a space and
+ * issue the event from WM_CHAR.
+ */
+ if (asciiKey == ' ') return null;
+ if (asciiKey != wParam) return null;
+ /*
+ * Feature in Windows. The virtual key VK_CANCEL is treated
+ * as both a virtual key and ASCII key by Windows. This
+ * means that a WM_CHAR with WPARAM=3 will be issued for
+ * this key. To avoid the extra SWT.KeyDown, look for
+ * VK_CANCEL and issue the event from WM_CHAR.
+ */
+ if (wParam == OS.VK_CANCEL) return null;
+ }
+
+ /*
+ * If the control key is not down at this point, then
+ * the key that was pressed was an accent key or a regular
+ * key such as 'A' or Shift+A. In that case, issue the
+ * key event from WM_CHAR.
+ */
+ if (OS.GetKeyState (OS.VK_CONTROL) >= 0) return null;
+
+ /*
+ * Get the shifted state or convert to lower case if necessary.
+ * If the user types Ctrl+A, LastAscii should be 'a', not 'A'.
+ * If the user types Ctrl+Shift+A, LastAscii should be 'A'.
+ * If the user types Ctrl+Shift+6, the value of LastAscii will
+ * depend on the international keyboard.
+ */
+ if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
+ display.lastAscii = display.shiftedKey (wParam);
+ if (display.lastAscii == 0) display.lastAscii = mapKey;
+ } else {
+ display.lastAscii = OS.CharLower ((short) mapKey);
+ }
+
+ /* Note that Ctrl+'@' is ASCII NUL and is delivered in WM_CHAR */
+ if (display.lastAscii == '@') return null;
+ display.lastAscii = display.controlKey (display.lastAscii);
+ }
+ if (!sendKeyEvent (SWT.KeyDown, OS.WM_KEYDOWN, wParam, lParam)) {
+ return LRESULT.ONE;
+ }
+ // widget could be disposed at this point
+ return null;
+}
+
+LRESULT wmKeyUp (int hwnd, int wParam, int lParam) {
+ Display display = this.display;
+
+ /* Check for hardware keys */
+ if (OS.IsWinCE) {
+ if (OS.VK_APP1 <= wParam && wParam <= OS.VK_APP6) {
+ display.lastKey = display.lastAscii = 0;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ Event event = new Event ();
+ event.detail = wParam - OS.VK_APP1 + 1;
+ /* Check the bit 30 to get the key state */
+ int type = (lParam & 0x40000000) != 0 ? SWT.HardKeyUp : SWT.HardKeyDown;
+ if (setInputState (event, type)) sendEvent (type, event);
+ // widget could be disposed at this point
+ return null;
+ }
+ }
+
+ /*
+ * If the key up is not hooked, reset last key
+ * and last ascii in case the key down is hooked.
+ */
+ if (!hooks (SWT.KeyUp) && !display.filters (SWT.KeyUp)) {
+ display.lastKey = display.lastAscii = 0;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ return null;
+ }
+
+ /* Map the virtual key. */
+ /*
+ * Bug in WinCE. MapVirtualKey() returns incorrect values.
+ * The fix is to rely on a key mappings table to determine
+ * whether the key event must be sent now or if a WM_CHAR
+ * event will follow. The key mappings table maps virtual
+ * keys to SWT key codes and does not contain mappings for
+ * Windows virtual keys like VK_A. Virtual keys that are
+ * both virtual and ASCII are a special case.
+ */
+ int mapKey = 0;
+ if (OS.IsWinCE) {
+ switch (wParam) {
+ case OS.VK_BACK: mapKey = SWT.BS; break;
+ case OS.VK_RETURN: mapKey = SWT.CR; break;
+ case OS.VK_DELETE: mapKey = SWT.DEL; break;
+ case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
+ case OS.VK_TAB: mapKey = SWT.TAB; break;
+ }
+ } else {
+ mapKey = OS.MapVirtualKey (wParam, 2);
+ }
+
+ /*
+ * Bug in Windows 95 and NT. When the user types an accent key such
+ * as ^ to get an accented character on a German keyboard, the accent
+ * key should be ignored and the next key that the user types is the
+ * accented key. The fix is to detect the accent key stroke (called
+ * a dead key) by testing the high bit of the value returned by
+ * MapVirtualKey (). A further problem is that the high bit on
+ * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
+ * They should both be bit 32.
+ */
+ if (OS.IsWinNT) {
+ if ((mapKey & 0x80000000) != 0) return null;
+ } else {
+ if ((mapKey & 0x8000) != 0) return null;
+ }
+ if (display.lastDead) return null;
+
+ /*
+ * NOTE: On Windows 98, keypad keys are virtual despite the
+ * fact that a WM_CHAR is issued. On Windows 2000 and XP,
+ * they are not virtual. Therefore it is necessary to force
+ * numeric keypad keys to be virtual.
+ */
+ display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
+ if (display.lastVirtual) {
+ display.lastKey = wParam;
+ } else {
+ /*
+ * Feature in Windows. The virtual key VK_CANCEL is treated
+ * as both a virtual key and ASCII key by Windows. This
+ * means that a WM_CHAR with WPARAM=3 will be issued for
+ * this key. In order to distingush between this key and
+ * Ctrl+C, mark the key as virtual.
+ */
+ if (wParam == OS.VK_CANCEL) display.lastVirtual = true;
+ if (display.lastKey == 0) {
+ display.lastAscii = 0;
+ display.lastNull = display.lastDead = false;
+ return null;
+ }
+ }
+ LRESULT result = null;
+ if (!sendKeyEvent (SWT.KeyUp, OS.WM_KEYUP, wParam, lParam)) {
+ result = LRESULT.ONE;
+ }
+ // widget could be disposed at this point
+ display.lastKey = display.lastAscii = 0;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+ return result;
+}
+
+LRESULT wmSysChar (int windowProc, int hwnd, int wParam, int lParam) {
+ Display display = this.display;
+ display.lastAscii = wParam;
+ display.lastNull = wParam == 0;
+
+ /* Do not issue a key down if a menu bar mnemonic was invoked */
+ if (!hooks (SWT.KeyDown) && !display.filters (SWT.KeyDown)) {
+ return null;
+ }
+
+ /* Call the window proc to determine whether it is a system key or mnemonic */
+ boolean oldKeyHit = display.mnemonicKeyHit;
+ display.mnemonicKeyHit = true;
+ //TEMPORARY CODE
+ int result = callWindowProc (OS.WM_SYSCHAR, wParam, lParam);
+ boolean consumed = false;
+ if (!display.mnemonicKeyHit) {
+ consumed = !sendKeyEvent (SWT.KeyDown, OS.WM_SYSCHAR, wParam, lParam);
+ // widget could be disposed at this point
+ }
+ consumed |= display.mnemonicKeyHit;
+ display.mnemonicKeyHit = oldKeyHit;
+ return consumed ? LRESULT.ONE : new LRESULT (result);
+}
+
+LRESULT wmSysKeyDown (int hwnd, int wParam, int lParam) {
+ /*
+ * Feature in Windows. When WM_SYSKEYDOWN is sent,
+ * the user pressed ALT+<key> or F10 to get to the
+ * menu bar. In order to issue events for F10 but
+ * ignore other key presses when the ALT is not down,
+ * make sure that either F10 was pressed or that ALT
+ * is pressed.
+ */
+ if (wParam != OS.VK_F10) {
+ /* Make sure WM_SYSKEYDOWN was sent by ALT-<aKey>. */
+ if ((lParam & 0x20000000) == 0) return null;
+ }
+
+ /* Ignore well known system keys */
+ switch (wParam) {
+ case OS.VK_F4: return null;
+ }
+
+ /* Ignore repeating modifier keys by testing key down state */
+ switch (wParam) {
+ case OS.VK_SHIFT:
+ case OS.VK_MENU:
+ case OS.VK_CONTROL:
+ case OS.VK_CAPITAL:
+ case OS.VK_NUMLOCK:
+ case OS.VK_SCROLL:
+ if ((lParam & 0x40000000) != 0) return null;
+ }
+
+ /* Clear last key and last ascii because a new key has been typed */
+ display.lastAscii = display.lastKey = 0;
+ display.lastVirtual = display.lastNull = display.lastDead = false;
+
+ /* If are going to get a WM_SYSCHAR, ignore this message. */
+ /*
+ * Bug in WinCE. MapVirtualKey() returns incorrect values.
+ * The fix is to rely on a key mappings table to determine
+ * whether the key event must be sent now or if a WM_CHAR
+ * event will follow. The key mappings table maps virtual
+ * keys to SWT key codes and does not contain mappings for
+ * Windows virtual keys like VK_A. Virtual keys that are
+ * both virtual and ASCII are a special case.
+ */
+ int mapKey = 0;
+ if (OS.IsWinCE) {
+ switch (wParam) {
+ case OS.VK_BACK: mapKey = SWT.BS; break;
+ case OS.VK_RETURN: mapKey = SWT.CR; break;
+ case OS.VK_DELETE: mapKey = SWT.DEL; break;
+ case OS.VK_ESCAPE: mapKey = SWT.ESC; break;
+ case OS.VK_TAB: mapKey = SWT.TAB; break;
+ }
+ } else {
+ mapKey = OS.MapVirtualKey (wParam, 2);
+ }
+ display.lastVirtual = mapKey == 0 || display.numpadKey (wParam) != 0;
+ if (display.lastVirtual) {
+ display.lastKey = wParam;
+ /*
+ * Feature in Windows. The virtual key VK_DELETE is not
+ * treated as both a virtual key and an ASCII key by Windows.
+ * Therefore, we will not receive a WM_SYSCHAR for this key.
+ * The fix is to treat VK_DELETE as a special case and map
+ * the ASCII value explictly (Delete is 0x7F).
+ */
+ if (display.lastKey == OS.VK_DELETE) display.lastAscii = 0x7F;
+
+ /* When a keypad key is typed, a WM_SYSCHAR is not issued */
+ if (OS.VK_NUMPAD0 <= display.lastKey && display.lastKey <= OS.VK_DIVIDE) {
+ display.lastAscii = display.numpadKey (display.lastKey);
+ }
+ } else {
+ /*
+ * Convert LastKey to lower case because Windows non-virtual
+ * keys that are also ASCII keys, such as like VK_A, are have
+ * upper case values in WM_SYSKEYDOWN despite the fact that the
+ * Shift was not pressed.
+ */
+ display.lastKey = OS.CharLower ((short) mapKey);
+
+ /*
+ * Feature in Windows 98. MapVirtualKey() indicates that
+ * a WM_SYSCHAR message will occur for Alt+Enter but
+ * this message never happens. The fix is to issue the
+ * event from WM_SYSKEYDOWN and map VK_RETURN to '\r'.
+ */
+ if (OS.IsWinNT) return null;
+ if (wParam != OS.VK_RETURN) return null;
+ display.lastAscii = '\r';
+ }
+
+ if (!sendKeyEvent (SWT.KeyDown, OS.WM_SYSKEYDOWN, wParam, lParam)) {
+ return LRESULT.ONE;
+ }
+ // widget could be disposed at this point
+ return null;
+}
+
+LRESULT wmSysKeyUp (int hwnd, int wParam, int lParam) {
+ return wmKeyUp (hwnd, wParam, lParam);
+}
}