| /* | |
| * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package java.awt; | |
| import java.awt.event.ActionEvent; | |
| import java.awt.event.AdjustmentEvent; | |
| import java.awt.event.ComponentEvent; | |
| import java.awt.event.FocusEvent; | |
| import java.awt.event.InputEvent; | |
| import java.awt.event.InputMethodEvent; | |
| import java.awt.event.ItemEvent; | |
| import java.awt.event.KeyEvent; | |
| import java.awt.event.MouseEvent; | |
| import java.awt.event.TextEvent; | |
| import java.awt.event.WindowEvent; | |
| import java.awt.peer.ComponentPeer; | |
| import java.awt.peer.LightweightPeer; | |
| import java.io.Serial; | |
| import java.util.EventObject; | |
| import sun.awt.AWTAccessor; | |
| /** | |
| * The root event class for all AWT events. | |
| * This class and its subclasses supersede the original | |
| * java.awt.Event class. | |
| * Subclasses of this root AWTEvent class defined outside of the | |
| * java.awt.event package should define event ID values greater than | |
| * the value defined by RESERVED_ID_MAX. | |
| * <p> | |
| * The event masks defined in this class are needed by Component subclasses | |
| * which are using Component.enableEvents() to select for event types not | |
| * selected by registered listeners. If a listener is registered on a | |
| * component, the appropriate event mask is already set internally by the | |
| * component. | |
| * <p> | |
| * The masks are also used to specify to which types of events an | |
| * AWTEventListener should listen. The masks are bitwise-ORed together | |
| * and passed to Toolkit.addAWTEventListener. | |
| * | |
| * @see Component#enableEvents | |
| * @see Toolkit#addAWTEventListener | |
| * | |
| * @see java.awt.event.ActionEvent | |
| * @see java.awt.event.AdjustmentEvent | |
| * @see java.awt.event.ComponentEvent | |
| * @see java.awt.event.ContainerEvent | |
| * @see java.awt.event.FocusEvent | |
| * @see java.awt.event.InputMethodEvent | |
| * @see java.awt.event.InvocationEvent | |
| * @see java.awt.event.ItemEvent | |
| * @see java.awt.event.HierarchyEvent | |
| * @see java.awt.event.KeyEvent | |
| * @see java.awt.event.MouseEvent | |
| * @see java.awt.event.MouseWheelEvent | |
| * @see java.awt.event.PaintEvent | |
| * @see java.awt.event.TextEvent | |
| * @see java.awt.event.WindowEvent | |
| * | |
| * @author Carl Quinn | |
| * @author Amy Fowler | |
| * @since 1.1 | |
| */ | |
| public abstract class AWTEvent extends EventObject { | |
| /** | |
| * @serial The private data. | |
| */ | |
| private byte[] bdata; | |
| /** | |
| * The event's id. | |
| * @serial | |
| * @see #getID() | |
| * @see #AWTEvent | |
| */ | |
| protected int id; | |
| /** | |
| * Controls whether or not the event is sent back down to the peer once the | |
| * source has processed it - false means it's sent to the peer; true means | |
| * it's not. Semantic events always have a 'true' value since they were | |
| * generated by the peer in response to a low-level event. | |
| * @serial | |
| * @see #consume | |
| * @see #isConsumed | |
| */ | |
| protected boolean consumed = false; | |
| transient boolean focusManagerIsDispatching = false; | |
| transient boolean isPosted; | |
| /** | |
| * Indicates whether this AWTEvent was generated by the system as | |
| * opposed to by user code. | |
| */ | |
| private transient boolean isSystemGenerated; | |
| /** | |
| * The event mask for selecting component events. | |
| */ | |
| public static final long COMPONENT_EVENT_MASK = 0x01; | |
| /** | |
| * The event mask for selecting container events. | |
| */ | |
| public static final long CONTAINER_EVENT_MASK = 0x02; | |
| /** | |
| * The event mask for selecting focus events. | |
| */ | |
| public static final long FOCUS_EVENT_MASK = 0x04; | |
| /** | |
| * The event mask for selecting key events. | |
| */ | |
| public static final long KEY_EVENT_MASK = 0x08; | |
| /** | |
| * The event mask for selecting mouse events. | |
| */ | |
| public static final long MOUSE_EVENT_MASK = 0x10; | |
| /** | |
| * The event mask for selecting mouse motion events. | |
| */ | |
| public static final long MOUSE_MOTION_EVENT_MASK = 0x20; | |
| /** | |
| * The event mask for selecting window events. | |
| */ | |
| public static final long WINDOW_EVENT_MASK = 0x40; | |
| /** | |
| * The event mask for selecting action events. | |
| */ | |
| public static final long ACTION_EVENT_MASK = 0x80; | |
| /** | |
| * The event mask for selecting adjustment events. | |
| */ | |
| public static final long ADJUSTMENT_EVENT_MASK = 0x100; | |
| /** | |
| * The event mask for selecting item events. | |
| */ | |
| public static final long ITEM_EVENT_MASK = 0x200; | |
| /** | |
| * The event mask for selecting text events. | |
| */ | |
| public static final long TEXT_EVENT_MASK = 0x400; | |
| /** | |
| * The event mask for selecting input method events. | |
| */ | |
| public static final long INPUT_METHOD_EVENT_MASK = 0x800; | |
| /** | |
| * The pseudo event mask for enabling input methods. | |
| * We're using one bit in the eventMask so we don't need | |
| * a separate field inputMethodsEnabled. | |
| */ | |
| static final long INPUT_METHODS_ENABLED_MASK = 0x1000; | |
| /** | |
| * The event mask for selecting paint events. | |
| */ | |
| public static final long PAINT_EVENT_MASK = 0x2000; | |
| /** | |
| * The event mask for selecting invocation events. | |
| */ | |
| public static final long INVOCATION_EVENT_MASK = 0x4000; | |
| /** | |
| * The event mask for selecting hierarchy events. | |
| */ | |
| public static final long HIERARCHY_EVENT_MASK = 0x8000; | |
| /** | |
| * The event mask for selecting hierarchy bounds events. | |
| */ | |
| public static final long HIERARCHY_BOUNDS_EVENT_MASK = 0x10000; | |
| /** | |
| * The event mask for selecting mouse wheel events. | |
| * @since 1.4 | |
| */ | |
| public static final long MOUSE_WHEEL_EVENT_MASK = 0x20000; | |
| /** | |
| * The event mask for selecting window state events. | |
| * @since 1.4 | |
| */ | |
| public static final long WINDOW_STATE_EVENT_MASK = 0x40000; | |
| /** | |
| * The event mask for selecting window focus events. | |
| * @since 1.4 | |
| */ | |
| public static final long WINDOW_FOCUS_EVENT_MASK = 0x80000; | |
| /** | |
| * WARNING: there are more mask defined privately. See | |
| * SunToolkit.GRAB_EVENT_MASK. | |
| */ | |
| /** | |
| * The maximum value for reserved AWT event IDs. Programs defining | |
| * their own event IDs should use IDs greater than this value. | |
| */ | |
| public static final int RESERVED_ID_MAX = 1999; | |
| /** | |
| * Use serialVersionUID from JDK 1.1 for interoperability. | |
| */ | |
| @Serial | |
| private static final long serialVersionUID = -1825314779160409405L; | |
| static { | |
| /* ensure that the necessary native libraries are loaded */ | |
| Toolkit.loadLibraries(); | |
| if (!GraphicsEnvironment.isHeadless()) { | |
| initIDs(); | |
| } | |
| AWTAccessor.setAWTEventAccessor( | |
| new AWTAccessor.AWTEventAccessor() { | |
| public void setPosted(AWTEvent ev) { | |
| ev.isPosted = true; | |
| } | |
| public void setSystemGenerated(AWTEvent ev) { | |
| ev.isSystemGenerated = true; | |
| } | |
| public boolean isSystemGenerated(AWTEvent ev) { | |
| return ev.isSystemGenerated; | |
| } | |
| public byte[] getBData(AWTEvent ev) { | |
| return ev.bdata; | |
| } | |
| public void setBData(AWTEvent ev, byte[] bdata) { | |
| ev.bdata = bdata; | |
| } | |
| }); | |
| } | |
| /** | |
| * Initialize JNI field and method IDs for fields that may be | |
| * accessed from C. | |
| */ | |
| private static native void initIDs(); | |
| /** | |
| * Constructs an AWTEvent object from the parameters of a 1.0-style event. | |
| * | |
| * @param event the old-style event | |
| * @deprecated It is recommended that {@link #AWTEvent(Object, int)} be used | |
| * instead | |
| */ | |
| @Deprecated(since = "9") | |
| public AWTEvent(Event event) { | |
| this(event.target, event.id); | |
| } | |
| /** | |
| * Constructs an AWTEvent object with the specified source object and type. | |
| * | |
| * @param source the object where the event originated | |
| * @param id the event type | |
| */ | |
| public AWTEvent(Object source, int id) { | |
| super(source); | |
| this.id = id; | |
| switch(id) { | |
| case ActionEvent.ACTION_PERFORMED: | |
| case ItemEvent.ITEM_STATE_CHANGED: | |
| case AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED: | |
| case TextEvent.TEXT_VALUE_CHANGED: | |
| consumed = true; | |
| break; | |
| default: | |
| } | |
| } | |
| /** | |
| * Retargets an event to a new source. This method is typically used to | |
| * retarget an event to a lightweight child Component of the original | |
| * heavyweight source. | |
| * <p> | |
| * This method is intended to be used only by event targeting subsystems, | |
| * such as client-defined KeyboardFocusManagers. It is not for general | |
| * client use. | |
| * | |
| * @param newSource the new Object to which the event should be dispatched | |
| * @since 1.4 | |
| */ | |
| public void setSource(Object newSource) { | |
| if (source == newSource) { | |
| return; | |
| } | |
| Component comp = null; | |
| if (newSource instanceof Component) { | |
| comp = (Component)newSource; | |
| while (comp != null && (comp.peer instanceof LightweightPeer)) { | |
| comp = comp.parent; | |
| } | |
| } | |
| synchronized (this) { | |
| source = newSource; | |
| if (comp != null) { | |
| ComponentPeer peer = comp.peer; | |
| if (peer != null) { | |
| nativeSetSource(peer); | |
| } | |
| } | |
| } | |
| } | |
| private native void nativeSetSource(ComponentPeer peer); | |
| /** | |
| * Returns the event type. | |
| * | |
| * @return the event's type id | |
| */ | |
| public int getID() { | |
| return id; | |
| } | |
| /** | |
| * Returns a String representation of this object. | |
| */ | |
| public String toString() { | |
| String srcName = null; | |
| if (source instanceof Component) { | |
| srcName = ((Component)source).getName(); | |
| } else if (source instanceof MenuComponent) { | |
| srcName = ((MenuComponent)source).getName(); | |
| } | |
| return getClass().getName() + "[" + paramString() + "] on " + | |
| (srcName != null? srcName : source); | |
| } | |
| /** | |
| * Returns a string representing the state of this {@code Event}. | |
| * This method is intended to be used only for debugging purposes, and the | |
| * content and format of the returned string may vary between | |
| * implementations. The returned string may be empty but may not be | |
| * {@code null}. | |
| * | |
| * @return a string representation of this event | |
| */ | |
| public String paramString() { | |
| return ""; | |
| } | |
| /** | |
| * Consumes this event, if this event can be consumed. Only low-level, | |
| * system events can be consumed | |
| */ | |
| protected void consume() { | |
| switch(id) { | |
| case KeyEvent.KEY_PRESSED: | |
| case KeyEvent.KEY_RELEASED: | |
| case MouseEvent.MOUSE_PRESSED: | |
| case MouseEvent.MOUSE_RELEASED: | |
| case MouseEvent.MOUSE_MOVED: | |
| case MouseEvent.MOUSE_DRAGGED: | |
| case MouseEvent.MOUSE_ENTERED: | |
| case MouseEvent.MOUSE_EXITED: | |
| case MouseEvent.MOUSE_WHEEL: | |
| case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: | |
| case InputMethodEvent.CARET_POSITION_CHANGED: | |
| consumed = true; | |
| break; | |
| default: | |
| // event type cannot be consumed | |
| } | |
| } | |
| /** | |
| * Returns whether this event has been consumed. | |
| * | |
| * @return {@code true} if this event has been consumed; | |
| * otherwise {@code false} | |
| */ | |
| protected boolean isConsumed() { | |
| return consumed; | |
| } | |
| /** | |
| * Converts a new event to an old one (used for compatibility). | |
| * If the new event cannot be converted (because no old equivalent | |
| * exists) then this returns null. | |
| * | |
| * Note: this method is here instead of in each individual new | |
| * event class in java.awt.event because we don't want to make | |
| * it public and it needs to be called from java.awt. | |
| */ | |
| @SuppressWarnings("deprecation") | |
| Event convertToOld() { | |
| Object src = getSource(); | |
| int newid = id; | |
| switch(id) { | |
| case KeyEvent.KEY_PRESSED: | |
| case KeyEvent.KEY_RELEASED: | |
| KeyEvent ke = (KeyEvent)this; | |
| if (ke.isActionKey()) { | |
| newid = (id == KeyEvent.KEY_PRESSED? | |
| Event.KEY_ACTION : Event.KEY_ACTION_RELEASE); | |
| } | |
| int keyCode = ke.getKeyCode(); | |
| if (keyCode == KeyEvent.VK_SHIFT || | |
| keyCode == KeyEvent.VK_CONTROL || | |
| keyCode == KeyEvent.VK_ALT) { | |
| return null; // suppress modifier keys in old event model. | |
| } | |
| // no mask for button1 existed in old Event - strip it out | |
| return new Event(src, ke.getWhen(), newid, 0, 0, | |
| Event.getOldEventKey(ke), | |
| (ke.getModifiers() & ~InputEvent.BUTTON1_MASK)); | |
| case MouseEvent.MOUSE_PRESSED: | |
| case MouseEvent.MOUSE_RELEASED: | |
| case MouseEvent.MOUSE_MOVED: | |
| case MouseEvent.MOUSE_DRAGGED: | |
| case MouseEvent.MOUSE_ENTERED: | |
| case MouseEvent.MOUSE_EXITED: | |
| MouseEvent me = (MouseEvent)this; | |
| // no mask for button1 existed in old Event - strip it out | |
| Event olde = new Event(src, me.getWhen(), newid, | |
| me.getX(), me.getY(), 0, | |
| (me.getModifiers() & ~InputEvent.BUTTON1_MASK)); | |
| olde.clickCount = me.getClickCount(); | |
| return olde; | |
| case FocusEvent.FOCUS_GAINED: | |
| return new Event(src, Event.GOT_FOCUS, null); | |
| case FocusEvent.FOCUS_LOST: | |
| return new Event(src, Event.LOST_FOCUS, null); | |
| case WindowEvent.WINDOW_CLOSING: | |
| case WindowEvent.WINDOW_ICONIFIED: | |
| case WindowEvent.WINDOW_DEICONIFIED: | |
| return new Event(src, newid, null); | |
| case ComponentEvent.COMPONENT_MOVED: | |
| if (src instanceof Frame || src instanceof Dialog) { | |
| Point p = ((Component)src).getLocation(); | |
| return new Event(src, 0, Event.WINDOW_MOVED, p.x, p.y, 0, 0); | |
| } | |
| break; | |
| case ActionEvent.ACTION_PERFORMED: | |
| ActionEvent ae = (ActionEvent)this; | |
| String cmd; | |
| if (src instanceof Button) { | |
| cmd = ((Button)src).getLabel(); | |
| } else if (src instanceof MenuItem) { | |
| cmd = ((MenuItem)src).getLabel(); | |
| } else { | |
| cmd = ae.getActionCommand(); | |
| } | |
| return new Event(src, 0, newid, 0, 0, 0, ae.getModifiers(), cmd); | |
| case ItemEvent.ITEM_STATE_CHANGED: | |
| ItemEvent ie = (ItemEvent)this; | |
| Object arg; | |
| if (src instanceof List) { | |
| newid = (ie.getStateChange() == ItemEvent.SELECTED? | |
| Event.LIST_SELECT : Event.LIST_DESELECT); | |
| arg = ie.getItem(); | |
| } else { | |
| newid = Event.ACTION_EVENT; | |
| if (src instanceof Choice) { | |
| arg = ie.getItem(); | |
| } else { // Checkbox | |
| arg = Boolean.valueOf(ie.getStateChange() == ItemEvent.SELECTED); | |
| } | |
| } | |
| return new Event(src, newid, arg); | |
| case AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED: | |
| AdjustmentEvent aje = (AdjustmentEvent)this; | |
| switch(aje.getAdjustmentType()) { | |
| case AdjustmentEvent.UNIT_INCREMENT: | |
| newid = Event.SCROLL_LINE_DOWN; | |
| break; | |
| case AdjustmentEvent.UNIT_DECREMENT: | |
| newid = Event.SCROLL_LINE_UP; | |
| break; | |
| case AdjustmentEvent.BLOCK_INCREMENT: | |
| newid = Event.SCROLL_PAGE_DOWN; | |
| break; | |
| case AdjustmentEvent.BLOCK_DECREMENT: | |
| newid = Event.SCROLL_PAGE_UP; | |
| break; | |
| case AdjustmentEvent.TRACK: | |
| if (aje.getValueIsAdjusting()) { | |
| newid = Event.SCROLL_ABSOLUTE; | |
| } | |
| else { | |
| newid = Event.SCROLL_END; | |
| } | |
| break; | |
| default: | |
| return null; | |
| } | |
| return new Event(src, newid, Integer.valueOf(aje.getValue())); | |
| default: | |
| } | |
| return null; | |
| } | |
| /** | |
| * Copies all private data from this event into that. | |
| * Space is allocated for the copied data that will be | |
| * freed when the that is finalized. Upon completion, | |
| * this event is not changed. | |
| */ | |
| void copyPrivateDataInto(AWTEvent that) { | |
| that.bdata = this.bdata; | |
| // Copy canAccessSystemClipboard value from this into that. | |
| if (this instanceof InputEvent && that instanceof InputEvent) { | |
| AWTAccessor.InputEventAccessor accessor | |
| = AWTAccessor.getInputEventAccessor(); | |
| boolean b = accessor.canAccessSystemClipboard((InputEvent) this); | |
| accessor.setCanAccessSystemClipboard((InputEvent) that, b); | |
| } | |
| that.isSystemGenerated = this.isSystemGenerated; | |
| } | |
| void dispatched() { | |
| if (this instanceof InputEvent) { | |
| AWTAccessor.getInputEventAccessor(). | |
| setCanAccessSystemClipboard((InputEvent) this, false); | |
| } | |
| } | |
| } // class AWTEvent |