/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.ide; import com.intellij.Patches; import com.intellij.ide.dnd.DnDManager; import com.intellij.ide.dnd.DnDManagerImpl; import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.ui.UISettings; import com.intellij.idea.IdeaApplication; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.diagnostic.FrequentEventDetector; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher; import com.intellij.openapi.keymap.impl.IdeMouseEventDispatcher; import com.intellij.openapi.keymap.impl.KeyState; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ExpirableRunnable; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.util.Alarm; import com.intellij.util.ReflectionUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.plaf.basic.ComboPopup; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.List; /** * @author Vladimir Kondratyev * @author Anton Katilin */ public class IdeEventQueue extends EventQueue { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.IdeEventQueue"); /** * Adding/Removing of "idle" listeners should be thread safe. */ private final Object myLock = new Object(); private final List myIdleListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final List myActivityListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final Alarm myIdleRequestsAlarm = new Alarm(); private final Alarm myIdleTimeCounterAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); private long myIdleTime; private final Map myListener2Request = new HashMap(); // IdleListener -> MyFireIdleRequest private final IdeKeyEventDispatcher myKeyEventDispatcher = new IdeKeyEventDispatcher(this); private final IdeMouseEventDispatcher myMouseEventDispatcher = new IdeMouseEventDispatcher(); private final IdePopupManager myPopupManager = new IdePopupManager(); private final ToolkitBugsProcessor myToolkitBugsProcessor = new ToolkitBugsProcessor(); private boolean mySuspendMode; /** * We exit from suspend mode when focus owner changes and no more WindowEvent.WINDOW_OPENED events *

* in the queue. If WINDOW_OPENED event does exists in the queues then we restart the alarm. */ private Component myFocusOwner; private final Runnable myExitSuspendModeRunnable = new ExitSuspendModeRunnable(); /** * We exit from suspend mode when this alarm is triggered and no mode WindowEvent.WINDOW_OPENED *

* events in the queue. If WINDOW_OPENED event does exist then we restart the alarm. */ private final Alarm mySuspendModeAlarm = new Alarm(); /** * Counter of processed events. It is used to assert that data context lives only inside single *

* Swing event. */ private int myEventCount; private boolean myIsInInputEvent = false; private AWTEvent myCurrentEvent = null; private long myLastActiveTime; private WindowManagerEx myWindowManager; private final Set myDispatchers = new LinkedHashSet(); private final Set myPostProcessors = new LinkedHashSet(); private final Set myReady = new HashSet(); private boolean myKeyboardBusy; private boolean myDispatchingFocusEvent; private int myInputMethodLock; private static class IdeEventQueueHolder { private static final IdeEventQueue INSTANCE = new IdeEventQueue(); } public static IdeEventQueue getInstance() { return IdeEventQueueHolder.INSTANCE; } private IdeEventQueue() { addIdleTimeCounterRequest(); final KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); keyboardFocusManager.addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent e) { final Application application = ApplicationManager.getApplication(); if (application == null) { // We can get focus event before application is initialized return; } application.assertIsDispatchThread(); final Window focusedWindow = keyboardFocusManager.getFocusedWindow(); final Component focusOwner = keyboardFocusManager.getFocusOwner(); if (mySuspendMode && focusedWindow != null && focusOwner != null && focusOwner != myFocusOwner && !(focusOwner instanceof Window)) { exitSuspendMode(); } } }); addDispatcher(new WindowsAltSupressor(), null); Application app = ApplicationManager.getApplication(); if (app != null && app.isUnitTestMode()) { //noinspection AssignmentToStaticFieldFromInstanceMethod ourAppIsLoaded = true; } } public void setWindowManager(final WindowManagerEx windowManager) { myWindowManager = windowManager; } private void addIdleTimeCounterRequest() { Application application = ApplicationManager.getApplication(); if (application != null && application.isUnitTestMode()) return; myIdleTimeCounterAlarm.cancelAllRequests(); myLastActiveTime = System.currentTimeMillis(); myIdleTimeCounterAlarm.addRequest(new Runnable() { @Override public void run() { myIdleTime += System.currentTimeMillis() - myLastActiveTime; addIdleTimeCounterRequest(); } }, 20000, ModalityState.NON_MODAL); } public boolean shouldNotTypeInEditor() { return myKeyEventDispatcher.isWaitingForSecondKeyStroke() || mySuspendMode; } private void enterSuspendMode() { mySuspendMode = true; myFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); mySuspendModeAlarm.cancelAllRequests(); mySuspendModeAlarm.addRequest(myExitSuspendModeRunnable, 750); } /** * Exits supend mode and pumps all suspended events. */ private void exitSuspendMode() { if (shallEnterSuspendMode()) { // We have to exit from suspend mode (focus owner changes or alarm is triggered) but // WINDOW_OPENED isn't dispatched yet. In this case we have to restart the alarm until // all WINDOW_OPENED event will be processed. mySuspendModeAlarm.cancelAllRequests(); mySuspendModeAlarm.addRequest(myExitSuspendModeRunnable, 250); } else { // Now we can pump all suspended events. mySuspendMode = false; myFocusOwner = null; // to prevent memory leaks } } public void addIdleListener(@NotNull final Runnable runnable, final int timeout) { LOG.assertTrue(timeout > 0); synchronized (myLock) { myIdleListeners.add(runnable); final MyFireIdleRequest request = new MyFireIdleRequest(runnable, timeout); myListener2Request.put(runnable, request); myIdleRequestsAlarm.addRequest(request, timeout); } } public void removeIdleListener(@NotNull final Runnable runnable) { synchronized (myLock) { final boolean wasRemoved = myIdleListeners.remove(runnable); if (!wasRemoved) { LOG.error("unknown runnable: " + runnable); } final MyFireIdleRequest request = myListener2Request.remove(runnable); LOG.assertTrue(request != null); myIdleRequestsAlarm.cancelRequest(request); } } public void addActivityListener(@NotNull final Runnable runnable) { synchronized (myLock) { myActivityListeners.add(runnable); } } public void addActivityListener(@NotNull final Runnable runnable, Disposable parentDisposable) { synchronized (myLock) { ContainerUtil.add(runnable, myActivityListeners, parentDisposable); } } public void removeActivityListener(@NotNull final Runnable runnable) { synchronized (myLock) { myActivityListeners.remove(runnable); } } public void addDispatcher(final EventDispatcher dispatcher, Disposable parent) { _addProcessor(dispatcher, parent, myDispatchers); } public void removeDispatcher(EventDispatcher dispatcher) { myDispatchers.remove(dispatcher); } public boolean containsDispatcher(EventDispatcher dispatcher) { return myDispatchers.contains(dispatcher); } public void addPostprocessor(EventDispatcher dispatcher, @Nullable Disposable parent) { _addProcessor(dispatcher, parent, myPostProcessors); } public void removePostprocessor(EventDispatcher dispatcher) { myPostProcessors.remove(dispatcher); } private static void _addProcessor(final EventDispatcher dispatcher, Disposable parent, final Set set) { set.add(dispatcher); if (parent != null) { Disposer.register(parent, new Disposable() { @Override public void dispose() { set.remove(dispatcher); } }); } } public int getEventCount() { return myEventCount; } public void setEventCount(int evCount) { myEventCount = evCount; } public AWTEvent getTrueCurrentEvent() { return myCurrentEvent; } private static class InertialMouseRouter { private static int MOUSE_WHEEL_RESTART_THRESHOLD = 50; private static Component wheelDestinationComponent = null; private static long lastMouseWheel = 0; private static AWTEvent changeSourceIfNeeded(AWTEvent awtEvent) { if (SystemInfo.isMac && Registry.is("ide.inertial.mouse.fix") && awtEvent instanceof MouseWheelEvent) { MouseWheelEvent mwe = (MouseWheelEvent) awtEvent; if (mwe.getWhen() - lastMouseWheel > MOUSE_WHEEL_RESTART_THRESHOLD) { wheelDestinationComponent = SwingUtilities.getDeepestComponentAt(mwe.getComponent(), mwe.getX(), mwe.getY()); } lastMouseWheel = System.currentTimeMillis(); MouseWheelEvent newMouseWheelEvent = new MouseWheelEvent( wheelDestinationComponent, mwe.getID(), lastMouseWheel, mwe.getModifiers(), mwe.getX(), mwe.getY(), mwe.getClickCount(), mwe.isPopupTrigger(), mwe.getScrollType(), mwe.getScrollAmount(), mwe.getWheelRotation() ); return newMouseWheelEvent; } return awtEvent; } } private static boolean ourAppIsLoaded = false; private static boolean appIsLoaded() { if (ourAppIsLoaded) return true; boolean loaded = IdeaApplication.isLoaded(); if (loaded) ourAppIsLoaded = true; return loaded; } @Override public void dispatchEvent(AWTEvent e) { if (!appIsLoaded()) { try { super.dispatchEvent(e); } catch (Throwable t) { processException(t); } return; } fixNonEnglishKeyboardLayouts(e); e = InertialMouseRouter.changeSourceIfNeeded(e); e = mapEvent(e); boolean wasInputEvent = myIsInInputEvent; myIsInInputEvent = e instanceof InputEvent || e instanceof InputMethodEvent || e instanceof WindowEvent || e instanceof ActionEvent; AWTEvent oldEvent = myCurrentEvent; myCurrentEvent = e; try { _dispatchEvent(e, false); } catch (Throwable t) { processException(t); } finally { myIsInInputEvent = wasInputEvent; myCurrentEvent = oldEvent; for (EventDispatcher each : myPostProcessors) { each.dispatch(e); } if (e instanceof KeyEvent) { maybeReady(); } } } private void processException(Throwable t) { if (!myToolkitBugsProcessor.process(t)) { PluginManager.processException(t); } } private static void fixNonEnglishKeyboardLayouts(AWTEvent e) { if (!Registry.is("ide.non.english.keyboard.layout.fix")) return; if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent)e; Integer keyCodeFromChar = CharToVKeyMap.get(ke.getKeyChar()); if (keyCodeFromChar != null) { if (keyCodeFromChar != ke.getKeyCode()) { // non-english layout ke.setKeyCode(keyCodeFromChar); } } } } private static AWTEvent mapEvent(AWTEvent e) { if (SystemInfo.isXWindow && e instanceof MouseEvent && ((MouseEvent)e).getButton() > 3) { MouseEvent src = (MouseEvent)e; if (src.getButton() < 6) { // Convert these events(buttons 4&5 in are produced by touchpad, they must be converted to horizontal scrolling events e = new MouseWheelEvent(src.getComponent(), src.getID(), src.getWhen(), src.getModifiers() | InputEvent.SHIFT_DOWN_MASK, src.getX(), src.getY(), 0, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, src.getClickCount(), src.getButton() == 4 ? -1 : 1); } else { // Here we "shift" events with buttons 6 and 7 to similar events with buttons 4 and 5 // See java.awt.InputEvent#BUTTON_DOWN_MASK, 1<<14 is 4th physical button, 1<<15 is 5th. //noinspection MagicConstant e = new MouseEvent(src.getComponent(), src.getID(), src.getWhen(), src.getModifiers() | (1 << 8 + src.getButton()), src.getX(), src.getY(), 1, src.isPopupTrigger(), src.getButton() - 2); } } return e; } public void _dispatchEvent(@NotNull AWTEvent e, boolean typeAheadFlushing) { if (e.getID() == MouseEvent.MOUSE_DRAGGED) { DnDManagerImpl dndManager = (DnDManagerImpl)DnDManager.getInstance(); if (dndManager != null) { dndManager.setLastDropHandler(null); } } myEventCount++; if (processAppActivationEvents(e)) return; if (!typeAheadFlushing) { fixStickyFocusedComponents(e); } if (!myPopupManager.isPopupActive()) { enterSuspendModeIfNeeded(e); } myKeyboardBusy = e instanceof KeyEvent || peekEvent(KeyEvent.KEY_PRESSED) != null || peekEvent(KeyEvent.KEY_RELEASED) != null || peekEvent(KeyEvent.KEY_TYPED) != null; if (e instanceof KeyEvent) { if (e.getID() == KeyEvent.KEY_RELEASED && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_SHIFT) { myMouseEventDispatcher.resetHorScrollingTracker(); } } if (!typeAheadFlushing && typeAheadDispatchToFocusManager(e)) { return; } if (e instanceof WindowEvent) { ActivityTracker.getInstance().inc(); } if (e instanceof MouseWheelEvent) { final MenuElement[] selectedPath = MenuSelectionManager.defaultManager().getSelectedPath(); if (selectedPath != null && selectedPath.length > 0 && !(selectedPath[0] instanceof ComboPopup)) { ((MouseWheelEvent)e).consume(); return; } } // Process "idle" and "activity" listeners if (e instanceof KeyEvent || e instanceof MouseEvent) { ActivityTracker.getInstance().inc(); synchronized (myLock) { myIdleRequestsAlarm.cancelAllRequests(); for (Runnable idleListener : myIdleListeners) { final MyFireIdleRequest request = myListener2Request.get(idleListener); if (request == null) { LOG.error("There is no request for " + idleListener); } int timeout = request.getTimeout(); myIdleRequestsAlarm.addRequest(request, timeout, ModalityState.NON_MODAL); } if (KeyEvent.KEY_PRESSED == e.getID() || KeyEvent.KEY_TYPED == e.getID() || MouseEvent.MOUSE_PRESSED == e.getID() || MouseEvent.MOUSE_RELEASED == e.getID() || MouseEvent.MOUSE_CLICKED == e.getID()) { addIdleTimeCounterRequest(); for (Runnable activityListener : myActivityListeners) { activityListener.run(); } } } } if (myPopupManager.isPopupActive() && myPopupManager.dispatch(e)) { if (myKeyEventDispatcher.isWaitingForSecondKeyStroke()) { myKeyEventDispatcher.setState(KeyState.STATE_INIT); } return; } for (EventDispatcher eachDispatcher : myDispatchers) { if (eachDispatcher.dispatch(e)) { return; } } if (e instanceof InputMethodEvent) { if (SystemInfo.isMac && myKeyEventDispatcher.isWaitingForSecondKeyStroke()) { return; } } if (e instanceof InputEvent && Patches.SPECIAL_INPUT_METHOD_PROCESSING) { final InputEvent inputEvent = (InputEvent)e; if (!inputEvent.getComponent().isShowing()) { return; } } if (e instanceof ComponentEvent && myWindowManager != null) { myWindowManager.dispatchComponentEvent((ComponentEvent)e); } if (e instanceof KeyEvent) { if (mySuspendMode || !myKeyEventDispatcher.dispatchKeyEvent((KeyEvent)e)) { defaultDispatchEvent(e); } else { ((KeyEvent)e).consume(); defaultDispatchEvent(e); } } else if (e instanceof MouseEvent) { MouseEvent me = (MouseEvent)e; if (myMouseEventDispatcher.patchClickCount(me) && me.getID() == MouseEvent.MOUSE_CLICKED) { final MouseEvent toDispatch = new MouseEvent(me.getComponent(), me.getID(), System.currentTimeMillis(), me.getModifiers(), me.getX(), me.getY(), 1, me.isPopupTrigger(), me.getButton()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dispatchEvent(toDispatch); } }); } if (me.getButton() != 0) { setLastClickEvent(me); } else if (lastClickEvent != null && Math.abs(System.currentTimeMillis() - lastClickTime) > 200){ setLastClickEvent(null);//Obsolete event } if (!myMouseEventDispatcher.dispatchMouseEvent(me)) { defaultDispatchEvent(e); } } else { defaultDispatchEvent(e); } } private MouseEvent lastClickEvent = null; private long lastClickTime = 0L; private void setLastClickEvent(@Nullable MouseEvent event) { lastClickEvent = event; lastClickTime = System.currentTimeMillis(); } public boolean wasRootRecentlyClicked(Component component) { if (component == null || lastClickEvent == null || lastClickEvent.getComponent() == null) return false; return SwingUtilities.getRoot(lastClickEvent.getComponent()) == SwingUtilities.getRoot(component); } private static void fixStickyWindow(KeyboardFocusManager mgr, Window wnd, String resetMethod) { Window showingWindow = wnd; if (wnd != null && !wnd.isShowing()) { while (showingWindow != null) { if (showingWindow.isShowing()) break; showingWindow = (Window)showingWindow.getParent(); } if (showingWindow == null) { final Frame[] allFrames = Frame.getFrames(); for (Frame each : allFrames) { if (each.isShowing()) { showingWindow = each; break; } } } if (showingWindow != null && showingWindow != wnd) { final Method setActive = ReflectionUtil.findMethod(ReflectionUtil.getClassDeclaredMethods(KeyboardFocusManager.class, false), resetMethod, Window.class); if (setActive != null) { try { setActive.invoke(mgr, (Window)showingWindow); } catch (Exception exc) { LOG.info(exc); } } } } } public void fixStickyFocusedComponents(@Nullable AWTEvent e) { if (e != null && !(e instanceof InputEvent)) return; final KeyboardFocusManager mgr = KeyboardFocusManager.getCurrentKeyboardFocusManager(); if (Registry.is("actionSystem.fixStickyFocusedWindows")) { fixStickyWindow(mgr, mgr.getActiveWindow(), "setGlobalActiveWindow"); fixStickyWindow(mgr, mgr.getFocusedWindow(), "setGlobalFocusedWindow"); } if (Registry.is("actionSystem.fixNullFocusedComponent")) { final Component focusOwner = mgr.getFocusOwner(); if (focusOwner == null || !focusOwner.isShowing() || focusOwner instanceof JFrame || focusOwner instanceof JDialog) { final Application app = ApplicationManager.getApplication(); if (app instanceof ApplicationEx && !((ApplicationEx) app).isLoaded()) { return; } boolean mouseEventsAhead = isMouseEventAhead(e); boolean focusTransferredNow = IdeFocusManager.getGlobalInstance().isFocusBeingTransferred(); boolean okToFixFocus = !mouseEventsAhead && !focusTransferredNow; if (okToFixFocus) { Window showingWindow = mgr.getActiveWindow(); if (showingWindow == null) { Method getNativeFocusOwner = ReflectionUtil.getDeclaredMethod(KeyboardFocusManager.class, "getNativeFocusOwner"); if (getNativeFocusOwner != null) { try { Object owner = getNativeFocusOwner.invoke(mgr); if (owner instanceof Component) { Component nativeFocusOwner = (Component)owner; if (nativeFocusOwner instanceof Window) { showingWindow = (Window)nativeFocusOwner; } else { showingWindow = SwingUtilities.getWindowAncestor(nativeFocusOwner); } } } catch (Exception e1) { LOG.debug(e1); } } } if (showingWindow != null) { final IdeFocusManager fm = IdeFocusManager.findInstanceByComponent(showingWindow); ExpirableRunnable maybeRequestDefaultFocus = new ExpirableRunnable() { @Override public void run() { if (getPopupManager().requestDefaultFocus(false)) return; final Application app = ApplicationManager.getApplication(); if (app != null && app.isActive()) { fm.requestDefaultFocus(false); } } @Override public boolean isExpired() { return !UIUtil.isMeaninglessFocusOwner(mgr.getFocusOwner()); } }; fm.revalidateFocus(maybeRequestDefaultFocus); } } } } } public static boolean isMouseEventAhead(@Nullable AWTEvent e) { IdeEventQueue queue = getInstance(); return e instanceof MouseEvent || queue.peekEvent(MouseEvent.MOUSE_PRESSED) != null || queue.peekEvent(MouseEvent.MOUSE_RELEASED) != null || queue.peekEvent(MouseEvent.MOUSE_CLICKED) != null; } private void enterSuspendModeIfNeeded(AWTEvent e) { if (e instanceof KeyEvent) { if (!mySuspendMode && shallEnterSuspendMode()) { enterSuspendMode(); } } } private boolean shallEnterSuspendMode() { return peekEvent(WindowEvent.WINDOW_OPENED) != null; } private static boolean processAppActivationEvents(AWTEvent e) { Application app = ApplicationManager.getApplication(); if (!(app instanceof ApplicationImpl)) return false; ApplicationImpl appImpl = (ApplicationImpl)app; if (e instanceof WindowEvent) { WindowEvent we = (WindowEvent)e; if (we.getID() == WindowEvent.WINDOW_GAINED_FOCUS && we.getWindow() != null) { if (we.getOppositeWindow() == null && !appImpl.isActive()) { appImpl.tryToApplyActivationState(true, we.getWindow()); } } else if (we.getID() == WindowEvent.WINDOW_LOST_FOCUS && we.getWindow() != null) { if (we.getOppositeWindow() == null && appImpl.isActive()) { appImpl.tryToApplyActivationState(false, we.getWindow()); } } } return false; } private void defaultDispatchEvent(final AWTEvent e) { try { myDispatchingFocusEvent = e instanceof FocusEvent; maybeReady(); fixStickyAlt(e); super.dispatchEvent(e); } catch (Throwable t) { processException(t); } finally { myDispatchingFocusEvent = false; } } private static Field stickyAltField; //IDEA-17359 private static void fixStickyAlt(AWTEvent e) { if (Registry.is("actionSystem.win.suppressAlt.new")) { if (SystemInfo.isWindows && UIManager.getLookAndFeel() instanceof WindowsLookAndFeel && e instanceof InputEvent && (((InputEvent)e).getModifiers() & (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK)) != 0 && !(e instanceof KeyEvent && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_ALT)) { try { if (stickyAltField == null) { stickyAltField = ReflectionUtil.getDeclaredField(Class.forName("com.sun.java.swing.plaf.windows.WindowsRootPaneUI$AltProcessor"), "menuCanceledOnPress"); } stickyAltField.set(null, true); } catch (Exception exception) { LOG.error(exception); } } } else if (SystemInfo.isWindowsXP && e instanceof KeyEvent && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_ALT) { ((KeyEvent)e).consume(); } } public boolean isDispatchingFocusEvent() { return myDispatchingFocusEvent; } private static boolean typeAheadDispatchToFocusManager(AWTEvent e) { if (e instanceof KeyEvent) { final KeyEvent event = (KeyEvent)e; if (!event.isConsumed()) { final IdeFocusManager focusManager = IdeFocusManager.findInstanceByComponent(event.getComponent()); return focusManager.dispatch(event); } } return false; } public void flushQueue() { while (true) { AWTEvent event = peekEvent(); if (event == null) return; try { AWTEvent event1 = getNextEvent(); dispatchEvent(event1); } catch (Exception e) { LOG.error(e); //? } } } public void pumpEventsForHierarchy(Component modalComponent, Condition exitCondition) { AWTEvent event; do { try { event = getNextEvent(); boolean eventOk = true; if (event instanceof InputEvent) { final Object s = event.getSource(); if (s instanceof Component) { Component c = (Component)s; Window modalWindow = modalComponent == null ? null : SwingUtilities.windowForComponent(modalComponent); while (c != null && c != modalWindow) c = c.getParent(); if (c == null) { eventOk = false; ((InputEvent)event).consume(); } } } if (eventOk) { dispatchEvent(event); } } catch (Throwable e) { LOG.error(e); event = null; } } while (!exitCondition.value(event)); } public interface EventDispatcher { boolean dispatch(AWTEvent e); } private final class MyFireIdleRequest implements Runnable { private final Runnable myRunnable; private final int myTimeout; public MyFireIdleRequest(@NotNull Runnable runnable, final int timeout) { myTimeout = timeout; myRunnable = runnable; } @Override public void run() { myRunnable.run(); synchronized (myLock) { if (myIdleListeners.contains(myRunnable)) // do not reschedule if not interested anymore { myIdleRequestsAlarm.addRequest(this, myTimeout, ModalityState.NON_MODAL); } } } public int getTimeout() { return myTimeout; } } private final class ExitSuspendModeRunnable implements Runnable { @Override public void run() { if (mySuspendMode) { exitSuspendMode(); } } } public long getIdleTime() { return myIdleTime; } public IdePopupManager getPopupManager() { return myPopupManager; } public IdeKeyEventDispatcher getKeyEventDispatcher() { return myKeyEventDispatcher; } /** * Same as {@link #blockNextEvents(java.awt.event.MouseEvent, com.intellij.ide.IdeEventQueue.BlockMode)} with blockMode equal * to COMPLETE. */ public void blockNextEvents(final MouseEvent e) { blockNextEvents(e, BlockMode.COMPLETE); } /** * When blockMode is COMPLETE, blocks following related mouse events completely, when blockMode is * ACTIONS only blocks performing actions bound to corresponding mouse shortcuts. */ public void blockNextEvents(final MouseEvent e, BlockMode blockMode) { myMouseEventDispatcher.blockNextEvents(e, blockMode); } public boolean isSuspendMode() { return mySuspendMode; } public boolean hasFocusEventsPending() { return peekEvent(FocusEvent.FOCUS_GAINED) != null || peekEvent(FocusEvent.FOCUS_LOST) != null; } private boolean isReady() { return !myKeyboardBusy && myKeyEventDispatcher.isReady(); } public void maybeReady() { flushReady(); } private void flushReady() { if (myReady.isEmpty() || !isReady()) return; Runnable[] ready = myReady.toArray(new Runnable[myReady.size()]); myReady.clear(); for (Runnable each : ready) { each.run(); } } public void doWhenReady(final Runnable runnable) { if (EventQueue.isDispatchThread()) { myReady.add(runnable); maybeReady(); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { myReady.add(runnable); maybeReady(); } }); } } public boolean isPopupActive() { return myPopupManager.isPopupActive(); } private static class WindowsAltSupressor implements EventDispatcher { private boolean myWaitingForAltRelease; private Robot myRobot; @Override public boolean dispatch(AWTEvent e) { boolean dispatch = true; if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent)e; final Component component = ke.getComponent(); boolean pureAlt = ke.getKeyCode() == KeyEvent.VK_ALT && (ke.getModifiers() | InputEvent.ALT_MASK) == InputEvent.ALT_MASK; if (!pureAlt) { myWaitingForAltRelease = false; } else { if (ApplicationManager.getApplication() == null || UISettings.getInstance() == null || !SystemInfo.isWindows || !Registry.is("actionSystem.win.suppressAlt") || !(UISettings.getInstance().HIDE_TOOL_STRIPES || UISettings.getInstance().PRESENTATION_MODE)) { return true; } if (ke.getID() == KeyEvent.KEY_PRESSED) { dispatch = !myWaitingForAltRelease; } else if (ke.getID() == KeyEvent.KEY_RELEASED) { if (myWaitingForAltRelease) { myWaitingForAltRelease = false; dispatch = false; } else if (component != null) { //noinspection SSBasedInspection SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { final Window window = component instanceof Window ? (Window)component : SwingUtilities.windowForComponent(component); if (window == null || !window.isActive()) { return; } myWaitingForAltRelease = true; if (myRobot == null) { myRobot = new Robot(); } myRobot.keyPress(KeyEvent.VK_ALT); myRobot.keyRelease(KeyEvent.VK_ALT); } catch (AWTException e1) { LOG.debug(e1); } } }); } } } } return !dispatch; } } public boolean isInputMethodEnabled() { return !SystemInfo.isMac || myInputMethodLock == 0; } public void disableInputMethods(Disposable parentDisposable) { myInputMethodLock++; Disposer.register(parentDisposable, new Disposable() { @Override public void dispose() { myInputMethodLock--; } }); } private final FrequentEventDetector myFrequentEventDetector = new FrequentEventDetector(1009, 100); @Override public void postEvent(AWTEvent theEvent) { myFrequentEventDetector.eventHappened(); super.postEvent(theEvent); } /** * @see com.intellij.ide.IdeEventQueue#blockNextEvents(java.awt.event.MouseEvent, com.intellij.ide.IdeEventQueue.BlockMode) */ public enum BlockMode { COMPLETE, ACTIONS } }