diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
index 5f5b8b722961..42f2a3434808 100644
--- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk
+++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
@@ -204,7 +204,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
LIBS_windows := kernel32.lib user32.lib gdi32.lib gdiplus.lib winspool.lib \
imm32.lib ole32.lib uuid.lib shell32.lib \
comdlg32.lib winmm.lib comctl32.lib shlwapi.lib \
- delayimp.lib jvm.lib $(WIN_JAVA_LIB) advapi32.lib dwmapi.lib $(A11Y_NVDA_ANNOUNCING_LIBS), \
+ delayimp.lib jvm.lib $(WIN_JAVA_LIB) advapi32.lib dwmapi.lib $(A11Y_NVDA_ANNOUNCING_LIBS) oleacc.lib, \
VERSIONINFO_RESOURCE := $(LIBAWT_VERSIONINFO_RESOURCE), \
EXTRA_RCFLAGS := $(LIBAWT_RCFLAGS), \
))
diff --git a/src/java.desktop/windows/classes/sun/awt/windows/AccessibleCaretLocationNotifier.java b/src/java.desktop/windows/classes/sun/awt/windows/AccessibleCaretLocationNotifier.java
new file mode 100644
index 000000000000..eaa088155f3a
--- /dev/null
+++ b/src/java.desktop/windows/classes/sun/awt/windows/AccessibleCaretLocationNotifier.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2024 JetBrains s.r.o.
+ * 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 sun.awt.windows;
+
+import sun.awt.AWTAccessor;
+import sun.java2d.SunGraphicsEnvironment;
+
+import javax.swing.*;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.text.JTextComponent;
+import java.awt.*;
+import java.awt.im.InputMethodRequests;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.lang.ref.WeakReference;
+
+/**
+ * Provides caret tracking support for assistive tools that don't work with Java Access Bridge.
+ * Specifically, it's targeted for the built-in Windows Magnifier.
+ * This class listens to caret change events of a currently focused JTextComponent and forwards them to the native code,
+ * which in turn sends them as Win32 IAccessible events.
+ *
+ * A typical high-level scenario of interaction with the magnifier:
+ *
+ * - Magnifier sends a WM_GETOBJECT window message to get accessible content of the window.
+ * - The message is handled in AwtComponent native class (awt_Component.cpp),
+ * which calls {@link #startCaretNotifier}.
+ * - We start listening for keyboard focus change events.
+ * - If at some point focus gets to a {@link JTextComponent}, we subscribe to its caret events.
+ * - When caret changes, we need to move the magnifier viewport to the new caret location.
+ * To achieve this, we create a Win32 IAccessible object for the caret (see AccessibleCaret.cpp),
+ * and send an event that its location was changed (EVENT_OBJECT_LOCATIONCHANGE).
+ * - Magnifier receives this event and sends WM_GETOBJECT message with OBJID_CARET argument
+ * to get the caret object and its location property. After that, it moves the viewport to the returned location.
+ *
+ * - When the {@link JTextComponent} loses focus, we stop listening to caret events
+ * and release the IAccessible caret object.
+ *
+ *
+ *
+ * The feature is enabled by default
+ * and can be disabled by setting sun.awt.windows.use.native.caret.accessibility.events property to false.
+ *
+ */
+@SuppressWarnings("unused") // Used from the native through JNI.
+class AccessibleCaretLocationNotifier implements PropertyChangeListener, CaretListener {
+ private static AccessibleCaretLocationNotifier caretNotifier;
+ private static final boolean nativeCaretEventsEnabled =
+ Boolean.parseBoolean(System.getProperty("sun.awt.windows.use.native.caret.accessibility.events", "true"));
+
+ private WeakReference currentFocusedComponent;
+ private long currentHwnd;
+
+ @SuppressWarnings("unused") // Called from the native through JNI.
+ public static void startCaretNotifier(long hwnd) {
+ if (nativeCaretEventsEnabled && caretNotifier == null) {
+ SwingUtilities.invokeLater(() -> {
+ caretNotifier = new AccessibleCaretLocationNotifier(hwnd);
+ KeyboardFocusManager cfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ cfm.addPropertyChangeListener("focusOwner", caretNotifier);
+ if (cfm.getFocusOwner() instanceof JTextComponent textComponent) {
+ caretNotifier.propertyChange(new PropertyChangeEvent(caretNotifier, "focusOwner", null, textComponent));
+ }
+ });
+ }
+ }
+
+ public AccessibleCaretLocationNotifier(long hwnd) {
+ currentHwnd = hwnd;
+ }
+
+ private static native void updateNativeCaretLocation(long hwnd, int x, int y, int width, int height);
+ private static native void releaseNativeCaret(long hwnd);
+ private static native void notifyFocusedWindowChanged(long hwnd);
+
+ @Override
+ public void propertyChange(PropertyChangeEvent e) {
+ Window w = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
+ if (w != null) {
+ WWindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w);
+ if (wp != null) {
+ long hwnd = wp.getHWnd();
+ if (currentHwnd != hwnd) {
+ currentHwnd = hwnd;
+ notifyFocusedWindowChanged(currentHwnd);
+ }
+ }
+ }
+
+ Object newFocusedComponent = e.getNewValue();
+ if (currentFocusedComponent != null) {
+ JTextComponent currentComponentStrong = currentFocusedComponent.get();
+ if (currentComponentStrong != null && newFocusedComponent != currentComponentStrong) {
+ currentComponentStrong.removeCaretListener(this);
+ currentFocusedComponent.clear();
+ currentFocusedComponent = null;
+ releaseNativeCaret(currentHwnd);
+ }
+ }
+
+ if (newFocusedComponent instanceof JTextComponent textComponent) {
+ currentFocusedComponent = new WeakReference<>(textComponent);
+ textComponent.addCaretListener(this);
+ // Trigger caret event when the text component receives focus to notify about the initial caret location.
+ caretUpdate(new CaretEvent(textComponent) {
+ // Dot and mark won't be used, so we can set any values.
+ @Override
+ public int getDot() { return 0; }
+
+ @Override
+ public int getMark() { return 0; }
+ });
+ }
+ }
+
+ @Override
+ public void caretUpdate(CaretEvent e) {
+ if (!(e.getSource() instanceof JTextComponent textComponent)) {
+ return;
+ }
+
+ SwingUtilities.invokeLater(() -> {
+ if (!textComponent.isShowing()) return;
+ InputMethodRequests imr = textComponent.getInputMethodRequests();
+ if (imr == null) return;
+ Rectangle caretRectangle = imr.getTextLocation(null);
+ if (caretRectangle == null) return;
+ caretRectangle.width = 1;
+
+ Container parent = textComponent.getParent();
+ if (parent != null && parent.isShowing()) {
+ // Make sure we don't go outside of parent bounds, which can happen in the case of scrollable components.
+ Rectangle parentBounds = parent.getBounds();
+ parentBounds.setLocation(parent.getLocationOnScreen());
+
+ if (!parentBounds.contains(caretRectangle)) {
+ caretRectangle = parentBounds.intersection(caretRectangle);
+ if (caretRectangle.isEmpty()) return;
+ }
+ }
+
+ caretRectangle = SunGraphicsEnvironment.toDeviceSpaceAbs(caretRectangle);
+
+ updateNativeCaretLocation(AccessibleCaretLocationNotifier.this.currentHwnd,
+ (int) caretRectangle.getX(), (int) caretRectangle.getY(),
+ (int) caretRectangle.getWidth(), (int) caretRectangle.getHeight());
+ });
+ }
+}
diff --git a/src/java.desktop/windows/native/libawt/windows/AccessibleCaret.cpp b/src/java.desktop/windows/native/libawt/windows/AccessibleCaret.cpp
new file mode 100644
index 000000000000..f8efce6fb03b
--- /dev/null
+++ b/src/java.desktop/windows/native/libawt/windows/AccessibleCaret.cpp
@@ -0,0 +1,270 @@
+/*
+* Copyright (c) 2024, JetBrains s.r.o.. 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.
+ *
+ * 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.
+ */
+
+#include "AccessibleCaret.h"
+
+/**
+ * This class implements Win32 IAccessible interface in a similar way to the system text caret.
+*/
+AccessibleCaret::AccessibleCaret()
+ : m_refCount(1), m_x(0), m_y(0), m_width(0), m_height(0) {
+}
+
+AccessibleCaret *AccessibleCaret::instance = NULL;
+
+bool AccessibleCaret::isCaretUsed = false;
+
+// IUnknown methods
+IFACEMETHODIMP_(ULONG) AccessibleCaret::AddRef() {
+ return InterlockedIncrement(&m_refCount);
+}
+
+IFACEMETHODIMP_(ULONG) AccessibleCaret::Release() {
+ ULONG count = InterlockedDecrement(&m_refCount);
+ if (count == 0) {
+ delete this;
+ }
+ return count;
+}
+
+IFACEMETHODIMP AccessibleCaret::QueryInterface(REFIID riid, void **ppInterface) {
+ if (ppInterface == NULL) {
+ return E_POINTER;
+ }
+
+ if (riid == IID_IUnknown || riid == IID_IDispatch || riid == IID_IAccessible) {
+ *ppInterface = static_cast(this);
+ AddRef();
+ return S_OK;
+ }
+
+ *ppInterface = NULL;
+ return E_NOINTERFACE;
+}
+
+// IDispatch methods
+IFACEMETHODIMP AccessibleCaret::GetTypeInfoCount(UINT *pctinfo) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid,
+ DISPID *rgdispid) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
+ DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo,
+ UINT *puArgErr) {
+ return E_NOTIMPL;
+}
+
+// IAccessible methods
+IFACEMETHODIMP AccessibleCaret::get_accParent(IDispatch **ppdispParent) {
+ if (ppdispParent == NULL) {
+ return E_POINTER;
+ }
+ *ppdispParent = NULL;
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accChildCount(long *pcountChildren) {
+ if (pcountChildren == NULL) {
+ return E_POINTER;
+ }
+ *pcountChildren = 0;
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accChild(VARIANT varChild, IDispatch **ppdispChild) {
+ *ppdispChild = NULL;
+ return S_FALSE;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accName(VARIANT varChild, BSTR *pszName) {
+ if (pszName == NULL) {
+ return E_POINTER;
+ }
+ *pszName = SysAllocString(L"Edit"); // Same name as the system caret.
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accValue(VARIANT varChild, BSTR *pszValue) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accDescription(VARIANT varChild, BSTR *pszDescription) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accRole(VARIANT varChild, VARIANT *pvarRole) {
+ if (pvarRole == NULL) {
+ return E_POINTER;
+ }
+
+ pvarRole->vt = VT_I4;
+ pvarRole->lVal = ROLE_SYSTEM_CARET;
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accState(VARIANT varChild, VARIANT *pvarState) {
+ if (pvarState == NULL) {
+ return E_POINTER;
+ }
+
+ pvarState->vt = VT_I4;
+ pvarState->lVal = 0; // The state without any flags, corresponds to "normal".
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accHelp(VARIANT varChild, BSTR *pszHelp) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accFocus(VARIANT *pvarChild) {
+ pvarChild->vt = VT_I4;
+ pvarChild->lVal = CHILDID_SELF;
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accSelection(VARIANT *pvarChildren) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::accSelect(long flagsSelect, VARIANT varChild) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight,
+ VARIANT varChild) {
+ if (pxLeft == NULL || pyTop == NULL || pcxWidth == NULL || pcyHeight == NULL) {
+ return E_POINTER;
+ }
+ isCaretUsed = true;
+
+ *pxLeft = m_x;
+ *pyTop = m_y;
+ *pcxWidth = m_width;
+ *pcyHeight = m_height;
+ return S_OK;
+}
+
+IFACEMETHODIMP AccessibleCaret::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::accHitTest(long xLeft, long yTop, VARIANT *pvarChild) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::accDoDefaultAction(VARIANT varChild) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::put_accName(VARIANT varChild, BSTR szName) {
+ return E_NOTIMPL;
+}
+
+IFACEMETHODIMP AccessibleCaret::put_accValue(VARIANT varChild, BSTR szValue) {
+ return E_NOTIMPL;
+}
+
+void AccessibleCaret::setLocation(long x, long y, long width, long height) {
+ m_x = x;
+ m_y = y;
+ m_width = width;
+ m_height = height;
+}
+
+
+extern "C" {
+/*
+ * Class: sun_awt_windows_AccessibleCaretLocationNotifier
+ * Method: updateNativeCaretLocation
+ * Signature: (JIIII)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_windows_AccessibleCaretLocationNotifier_updateNativeCaretLocation(
+ JNIEnv *env, jclass jClass,
+ jlong jHwnd, jint x, jint y, jint width, jint height) {
+ HWND hwnd = reinterpret_cast(jHwnd);
+ if (AccessibleCaret::instance == NULL) {
+ AccessibleCaret::instance = new AccessibleCaret();
+ // Notify with Object ID "OBJID_CARET".
+ // After that, an assistive tool will send a WM_GETOBJECT message with this ID,
+ // and we can return the caret instance.
+ NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, CHILDID_SELF);
+ NotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, CHILDID_SELF);
+ }
+ AccessibleCaret::instance->setLocation(x, y, width, height);
+ NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_CARET, CHILDID_SELF);
+}
+
+/*
+ * Class: sun_awt_windows_AccessibleCaretLocationNotifier
+ * Method: releaseNativeCaret
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_windows_AccessibleCaretLocationNotifier_releaseNativeCaret(
+ JNIEnv *env, jclass jClass, jlong jHwnd) {
+ if (AccessibleCaret::instance != NULL) {
+ HWND hwnd = reinterpret_cast(jHwnd);
+ AccessibleCaret::instance->Release();
+ AccessibleCaret::instance = NULL;
+ NotifyWinEvent(EVENT_OBJECT_HIDE, hwnd, OBJID_CARET, CHILDID_SELF);
+ NotifyWinEvent(EVENT_OBJECT_DESTROY, hwnd, OBJID_CARET, CHILDID_SELF);
+ }
+}
+
+/*
+ * Class: sun_awt_windows_AccessibleCaretLocationNotifier
+ * Method: notifyFocusedWindowChanged
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_windows_AccessibleCaretLocationNotifier_notifyFocusedWindowChanged(
+ JNIEnv *env, jclass jClass, jlong jHwnd) {
+ HWND hwnd = reinterpret_cast(jHwnd);
+ // This is a workaround to make sure the foreground window is set to the actual focused window.
+ // Otherwise, in some cases, e.g., when opening a popup,
+ // the root frame can still stay as the foreground window instead of the popup,
+ // and Magnifier will be focused on it instead of the popup.
+ // We only do it if the caret object is actually used to minimize risks.
+ if (AccessibleCaret::isCaretUsed && ::GetForegroundWindow() != hwnd) {
+ ::SetForegroundWindow(hwnd);
+ }
+}
+} /* extern "C" */
diff --git a/src/java.desktop/windows/native/libawt/windows/AccessibleCaret.h b/src/java.desktop/windows/native/libawt/windows/AccessibleCaret.h
new file mode 100644
index 000000000000..e1c2b0a4c135
--- /dev/null
+++ b/src/java.desktop/windows/native/libawt/windows/AccessibleCaret.h
@@ -0,0 +1,80 @@
+/*
+* Copyright (c) 2024, JetBrains s.r.o.. 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.
+ *
+ * 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.
+ */
+
+#ifndef ACCESSIBLECARET_H
+#define ACCESSIBLECARET_H
+#include "jni.h"
+#include
+
+class AccessibleCaret : public IAccessible {
+public:
+ AccessibleCaret();
+
+ static AccessibleCaret *instance;
+ static bool isCaretUsed;
+
+ // IUnknown methods.
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface);
+
+ // IDispatch methods.
+ IFACEMETHODIMP GetTypeInfoCount(UINT *pctinfo);
+ IFACEMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo);
+ IFACEMETHODIMP GetIDsOfNames(REFIID riid, __in_ecount(cNames)
+ OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid);
+ IFACEMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
+ WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult,
+ EXCEPINFO *pexcepinfo, UINT *puArgErr);
+
+ // IAccessible methods
+ IFACEMETHODIMP get_accParent(IDispatch **ppdispParent);
+ IFACEMETHODIMP get_accChildCount(long *pcountChildren);
+ IFACEMETHODIMP get_accChild(VARIANT varChild, IDispatch **ppdispChild);
+ IFACEMETHODIMP get_accName(VARIANT varChild, BSTR *pszName);
+ IFACEMETHODIMP get_accValue(VARIANT varChild, BSTR *pszValue);
+ IFACEMETHODIMP get_accDescription(VARIANT varChild, BSTR *pszDescription);
+ IFACEMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole);
+ IFACEMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState);
+ IFACEMETHODIMP get_accHelp(VARIANT varChild, BSTR *pszHelp);
+ IFACEMETHODIMP get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic);
+ IFACEMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut);
+ IFACEMETHODIMP get_accFocus(VARIANT *pvarChild);
+ IFACEMETHODIMP get_accSelection(VARIANT *pvarChildren);
+ IFACEMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction);
+ IFACEMETHODIMP accSelect(long flagsSelect, VARIANT varChild);
+ IFACEMETHODIMP accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild);
+ IFACEMETHODIMP accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt);
+ IFACEMETHODIMP accHitTest(long xLeft, long yTop, VARIANT *pvarChild);
+ IFACEMETHODIMP accDoDefaultAction(VARIANT varChild);
+ IFACEMETHODIMP put_accName(VARIANT varChild, BSTR szName);
+ IFACEMETHODIMP put_accValue(VARIANT varChild, BSTR szValue);
+
+ void setLocation(long x, long y, long width, long height);
+
+private:
+ ULONG m_refCount;
+ int m_x, m_y, m_width, m_height;
+};
+
+#endif //ACCESSIBLECARET_H
diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
index 4e383d91cc8c..209e3618b0e8 100644
--- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp
@@ -49,6 +49,7 @@
#include "Hashtable.h"
#include "ComCtl32Util.h"
#include "math.h"
+#include "AccessibleCaret.h"
#include
@@ -2071,6 +2072,31 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
if (::IsWindow(AwtWindow::GetModalBlocker(GetHWnd()))) {
mr = mrConsume;
}
+ break;
+ }
+ case WM_GETOBJECT:
+ {
+ // We've got a WM_GETOBJECT message which was likely sent by an assistive tool.
+ // Therefore, we can start generating native caret accessibility events.
+ DWORD objId = static_cast(static_cast(lParam));
+ if (objId == OBJID_CLIENT) {
+ JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
+ if (env != NULL) {
+ jclass cls = env->FindClass("sun/awt/windows/AccessibleCaretLocationNotifier");
+ if (cls != NULL) {
+ jmethodID mid = env->GetStaticMethodID(cls, "startCaretNotifier", "(J)V");
+ if (mid != NULL) {
+ env->CallStaticVoidMethod(cls, mid, reinterpret_cast(GetHWnd()));
+ }
+ }
+ }
+ } else if (objId == OBJID_CARET) {
+ if (AccessibleCaret::instance != NULL) {
+ retValue = LresultFromObject(IID_IAccessible, wParam, AccessibleCaret::instance);
+ mr = mrConsume;
+ }
+ }
+ break;
}
}