Bug 128647 [RFE] Handler for WM_COPY/WM_CUT/WM_PASTE/WM_CLEAR r=ere+roc, sr=roc

This commit is contained in:
Masayuki Nakano 2009-08-08 00:11:17 +09:00
Родитель 7f7f2917fc
Коммит 1f7985543f
8 изменённых файлов: 429 добавлений и 41 удалений

Просмотреть файл

@ -151,6 +151,8 @@
#ifdef MOZ_XUL
#include "nsTreeBodyFrame.h"
#endif
#include "nsIFocusController.h"
#include "nsIController.h"
#ifdef XP_MACOSX
#include <Carbon/Carbon.h>
@ -1195,6 +1197,16 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
handler.OnSelectionEvent((nsSelectionEvent*)aEvent);
}
break;
case NS_CONTENT_COMMAND_CUT:
case NS_CONTENT_COMMAND_COPY:
case NS_CONTENT_COMMAND_PASTE:
case NS_CONTENT_COMMAND_DELETE:
case NS_CONTENT_COMMAND_UNDO:
case NS_CONTENT_COMMAND_REDO:
{
DoContentCommandEvent(static_cast<nsContentCommandEvent*>(aEvent));
}
break;
}
return NS_OK;
}
@ -4205,3 +4217,56 @@ nsEventStateManager::IsShellVisible(nsIDocShell* aShell)
return isVisible;
}
nsresult
nsEventStateManager::DoContentCommandEvent(nsContentCommandEvent* aEvent)
{
EnsureDocument(mPresContext);
NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->GetWindow()));
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsIFocusController* fc = window->GetRootFocusController();
NS_ENSURE_TRUE(fc, NS_ERROR_FAILURE);
const char* cmd;
switch (aEvent->message) {
case NS_CONTENT_COMMAND_CUT:
cmd = "cmd_cut";
break;
case NS_CONTENT_COMMAND_COPY:
cmd = "cmd_copy";
break;
case NS_CONTENT_COMMAND_PASTE:
cmd = "cmd_paste";
break;
case NS_CONTENT_COMMAND_DELETE:
cmd = "cmd_delete";
break;
case NS_CONTENT_COMMAND_UNDO:
cmd = "cmd_undo";
break;
case NS_CONTENT_COMMAND_REDO:
cmd = "cmd_redo";
break;
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
nsCOMPtr<nsIController> controller;
nsresult rv = fc->GetControllerForCommand(cmd, getter_AddRefs(controller));
NS_ENSURE_SUCCESS(rv, rv);
if (!controller) {
// When GetControllerForCommand succeeded but there is no controller, the
// command isn't supported.
aEvent->mIsEnabled = PR_FALSE;
} else {
PRBool canDoIt;
rv = controller->IsCommandEnabled(cmd, &canDoIt);
NS_ENSURE_SUCCESS(rv, rv);
aEvent->mIsEnabled = canDoIt;
if (canDoIt && !aEvent->mOnlyEnabledCheck) {
rv = controller->DoCommand(cmd);
NS_ENSURE_SUCCESS(rv, rv);
}
}
aEvent->mSucceeded = PR_TRUE;
return NS_OK;
}

Просмотреть файл

@ -326,6 +326,8 @@ protected:
*/
void FillInEventFromGestureDown(nsMouseEvent* aEvent);
nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent);
PRInt32 mLockCursor;
nsWeakFrame mCurrentTarget;

Просмотреть файл

@ -5972,10 +5972,7 @@ PresShell::HandleEvent(nsIView *aView,
#endif
// key and IME events must be targeted at the presshell for the focused frame
if (!sDontRetargetEvents &&
(NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent) ||
NS_IS_QUERY_CONTENT_EVENT(aEvent) || NS_IS_SELECTION_EVENT(aEvent) ||
NS_IS_CONTEXT_MENU_KEY(aEvent))) {
if (!sDontRetargetEvents && NS_IsEventTargetedAtFocusedWindow(aEvent)) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (!fm)
return NS_ERROR_FAILURE;
@ -6060,10 +6057,7 @@ PresShell::HandleEvent(nsIView *aView,
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
PRBool dispatchUsingCoordinates =
!NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) &&
!NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) &&
!NS_IS_PLUGIN_EVENT(aEvent);
PRBool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent);
// if this event has no frame, we need to retarget it at a parent
// view that has a frame.

Просмотреть файл

@ -1101,11 +1101,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
nsView* view = baseView;
PRBool capturedEvent = PR_FALSE;
if (!NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) &&
!NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) &&
!NS_IS_QUERY_CONTENT_EVENT(aEvent) && !NS_IS_PLUGIN_EVENT(aEvent) &&
!NS_IS_SELECTION_EVENT(aEvent) &&
aEvent->eventStructType != NS_ACCESSIBLE_EVENT) {
if (NS_IsEventUsingCoordinates(aEvent)) {
// will dispatch using coordinates. Pretty bogus but it's consistent
// with what presshell does.
view = GetDisplayRootFor(baseView);

Просмотреть файл

@ -88,6 +88,7 @@ class nsReconversionEvent;
class nsTooltipEvent;
class nsMenuEvent;
class nsSimpleGestureEvent;
class nsContentCommandEvent;
struct nsTextEventReply;

Просмотреть файл

@ -104,6 +104,7 @@ class nsHashKey;
#define NS_NOTIFYPAINT_EVENT 36
#define NS_SIMPLE_GESTURE_EVENT 37
#define NS_SELECTION_EVENT 38
#define NS_CONTENT_COMMAND_EVENT 39
// These flags are sort of a mess. They're sort of shared between event
// listener flags and event flags, but only some of them. You've been
@ -419,6 +420,15 @@ class nsHashKey;
// Clear any previous selection and set the given range as the selection
#define NS_SELECTION_SET (NS_SELECTION_EVENT_START)
// Events of commands for the contents
#define NS_CONTENT_COMMAND_EVENT_START 3800
#define NS_CONTENT_COMMAND_CUT (NS_CONTENT_COMMAND_EVENT_START)
#define NS_CONTENT_COMMAND_COPY (NS_CONTENT_COMMAND_EVENT_START+1)
#define NS_CONTENT_COMMAND_PASTE (NS_CONTENT_COMMAND_EVENT_START+2)
#define NS_CONTENT_COMMAND_DELETE (NS_CONTENT_COMMAND_EVENT_START+3)
#define NS_CONTENT_COMMAND_UNDO (NS_CONTENT_COMMAND_EVENT_START+4)
#define NS_CONTENT_COMMAND_REDO (NS_CONTENT_COMMAND_EVENT_START+5)
/**
* Return status for event processors, nsEventStatus, is defined in
* nsEvent.h.
@ -1134,6 +1144,23 @@ public:
PRPackedBool mSucceeded;
};
class nsContentCommandEvent : public nsGUIEvent
{
public:
nsContentCommandEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget,
PRBool aOnlyEnabledCheck = PR_FALSE) :
nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_CONTENT_COMMAND_EVENT),
mOnlyEnabledCheck(PRPackedBool(aOnlyEnabledCheck)),
mSucceeded(PR_FALSE), mIsEnabled(PR_FALSE)
{
}
PRPackedBool mOnlyEnabledCheck; // [in]
PRPackedBool mSucceeded; // [out]
PRPackedBool mIsEnabled; // [out]
};
/**
* MenuItem event
*
@ -1301,6 +1328,14 @@ enum nsDragDropEventStatus {
#define NS_IS_SELECTION_EVENT(evnt) \
(((evnt)->message == NS_SELECTION_SET))
#define NS_IS_CONTENT_COMMAND_EVENT(evnt) \
(((evnt)->message == NS_CONTENT_COMMAND_CUT) || \
((evnt)->message == NS_CONTENT_COMMAND_COPY) || \
((evnt)->message == NS_CONTENT_COMMAND_PASTE) || \
((evnt)->message == NS_CONTENT_COMMAND_DELETE) || \
((evnt)->message == NS_CONTENT_COMMAND_UNDO) || \
((evnt)->message == NS_CONTENT_COMMAND_REDO))
#define NS_IS_PLUGIN_EVENT(evnt) \
(((evnt)->message == NS_PLUGIN_EVENT))
@ -1485,10 +1520,27 @@ inline PRBool NS_TargetUnfocusedEventToLastFocusedContent(nsEvent* aEvent)
// send the events to pre-focused element.
return NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent) ||
NS_IS_PLUGIN_EVENT(aEvent);
NS_IS_PLUGIN_EVENT(aEvent) || NS_IS_CONTENT_COMMAND_EVENT(aEvent);
#else
return PR_FALSE;
#endif
}
inline PRBool NS_IsEventUsingCoordinates(nsEvent* aEvent)
{
return !NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) &&
!NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) &&
!NS_IS_QUERY_CONTENT_EVENT(aEvent) && !NS_IS_PLUGIN_EVENT(aEvent) &&
!NS_IS_SELECTION_EVENT(aEvent) &&
!NS_IS_CONTENT_COMMAND_EVENT(aEvent) &&
aEvent->eventStructType != NS_ACCESSIBLE_EVENT;
}
inline PRBool NS_IsEventTargetedAtFocusedWindow(nsEvent* aEvent)
{
return NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent) ||
NS_IS_QUERY_CONTENT_EVENT(aEvent) || NS_IS_SELECTION_EVENT(aEvent) ||
NS_IS_CONTEXT_MENU_KEY(aEvent) || NS_IS_CONTENT_COMMAND_EVENT(aEvent);
}
#endif // nsGUIEvent_h__

Просмотреть файл

@ -166,6 +166,7 @@
#include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
#include <zmouse.h>
#include <pbt.h>
#include <Richedit.h>
#endif // !defined(WINCE)
#if defined(ACCESSIBILITY)
@ -4250,6 +4251,92 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
break;
#endif // !defined(WINCE)
case WM_CLEAR:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_DELETE, this);
DispatchWindowEvent(&command);
result = PR_TRUE;
}
break;
case WM_CUT:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_CUT, this);
DispatchWindowEvent(&command);
result = PR_TRUE;
}
break;
case WM_COPY:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_COPY, this);
DispatchWindowEvent(&command);
result = PR_TRUE;
}
break;
case WM_PASTE:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE, this);
DispatchWindowEvent(&command);
result = PR_TRUE;
}
break;
#ifndef WINCE
case EM_UNDO:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO, this);
DispatchWindowEvent(&command);
*aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
result = PR_TRUE;
}
break;
case EM_REDO:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO, this);
DispatchWindowEvent(&command);
*aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
result = PR_TRUE;
}
break;
case EM_CANPASTE:
{
// Support EM_CANPASTE message only when wParam isn't specified or
// is plain text format.
if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) {
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_PASTE,
this, PR_TRUE);
DispatchWindowEvent(&command);
*aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
result = PR_TRUE;
}
}
break;
case EM_CANUNDO:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_UNDO,
this, PR_TRUE);
DispatchWindowEvent(&command);
*aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
result = PR_TRUE;
}
break;
case EM_CANREDO:
{
nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_REDO,
this, PR_TRUE);
DispatchWindowEvent(&command);
*aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled);
result = PR_TRUE;
}
break;
#endif
default:
{
#ifdef NS_ENABLE_TSF

Просмотреть файл

@ -49,6 +49,7 @@
#include <msctf.h>
#include <textstor.h>
#include <Richedit.h>
#include "TestHarness.h"
@ -138,6 +139,7 @@ protected:
PRBool TestComposition(void);
PRBool TestNotification(void);
PRBool TestContentEvents(void);
PRBool TestEditMessages(void);
PRBool TestApp::TestSelectionInternal(char* aTestName,
LONG aStart,
@ -155,6 +157,8 @@ protected:
LONG aNewEnd);
nsresult GetSelCon(nsISelectionController** aSelCon);
PRBool GetWidget(nsIWidget** aWidget);
PRBool mFailed;
nsString mTestString;
nsRefPtr<TSFMgrImpl> mMgr;
@ -1654,6 +1658,8 @@ TestApp::OnStateChange(nsIWebProgress *aWebProgress,
printf("Testing content events...\n");
if (TestContentEvents())
passed("TestContentEvents");
if (RunTest(&TestApp::TestEditMessages))
passed("TestEditMessages");
if (RunTest(&TestApp::TestFocus, PR_FALSE))
passed("TestFocus");
@ -2661,19 +2667,7 @@ TestApp::TestNotification(void)
}
nsCOMPtr<nsIWidget> widget;
nsCOMPtr<nsIDocShell> docShell;
nsr = mWindow->GetDocShell(getter_AddRefs(docShell));
if (NS_SUCCEEDED(nsr) && docShell) {
nsCOMPtr<nsIPresShell> presShell;
nsr = docShell->GetPresShell(getter_AddRefs(presShell));
if (NS_SUCCEEDED(nsr) && presShell) {
nsCOMPtr<nsIViewManager> viewManager = presShell->GetViewManager();
if (viewManager) {
nsr = viewManager->GetRootWidget(getter_AddRefs(widget));
}
}
}
if (!(NS_SUCCEEDED(nsr) && widget)) {
if (!GetWidget(getter_AddRefs(widget))) {
fail("TestNotification: get nsIWidget");
return PR_FALSE;
}
@ -2728,19 +2722,7 @@ TestApp::TestContentEvents(void)
mTextArea->Focus();
nsCOMPtr<nsIWidget> widget;
nsCOMPtr<nsIDocShell> docShell;
nsresult nsr = mWindow->GetDocShell(getter_AddRefs(docShell));
if (NS_SUCCEEDED(nsr) && docShell) {
nsCOMPtr<nsIPresShell> presShell;
nsr = docShell->GetPresShell(getter_AddRefs(presShell));
if (NS_SUCCEEDED(nsr) && presShell) {
nsCOMPtr<nsIViewManager> viewManager = presShell->GetViewManager();
if (viewManager) {
nsr = viewManager->GetRootWidget(getter_AddRefs(widget));
}
}
}
if (NS_FAILED(nsr) || !widget) {
if (!GetWidget(getter_AddRefs(widget))) {
fail("TestContentEvents: get nsIWidget");
return PR_FALSE;
}
@ -2752,7 +2734,7 @@ TestApp::TestContentEvents(void)
}
nsIntRect widgetRect, topLevelRect;
nsr = widget->GetScreenBounds(widgetRect);
nsresult nsr = widget->GetScreenBounds(widgetRect);
if (NS_FAILED(nsr)) {
fail("TestContentEvents: get widget rect");
return PR_FALSE;
@ -2866,6 +2848,215 @@ TestApp::TestContentEvents(void)
return result;
}
PRBool
TestApp::TestEditMessages(void)
{
mTestString = NS_LITERAL_STRING(
"This is a test of\nthe native editing command messages");
// 0123456789012345678901 2345678901234567890123456789012
// 0 1 2 3 4 5
// The native text string is increased by converting \n to \r\n.
PRUint32 testStringLength = mTestString.Length() + 1;
mTextArea->SetValue(mTestString);
mTextArea->Focus();
nsCOMPtr<nsIWidget> widget;
if (!GetWidget(getter_AddRefs(widget))) {
fail("TestEditMessages: get nsIWidget");
return PR_FALSE;
}
HWND wnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
PRBool result = PR_TRUE;
if (!::SendMessage(wnd, EM_CANUNDO, 0, 0)) {
fail("TestEditMessages: EM_CANUNDO");
return PR_FALSE;
}
if (::SendMessage(wnd, EM_CANREDO, 0, 0)) {
fail("TestEditMessages: EM_CANREDO #1");
return PR_FALSE;
}
if (!::SendMessage(wnd, EM_UNDO, 0, 0)) {
fail("TestEditMessages: EM_UNDO #1");
return PR_FALSE;
}
nsAutoString str;
mTextArea->GetValue(str);
if (str == mTestString) {
fail("TestEditMessage: EM_UNDO #1, failed to execute");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
if (!::SendMessage(wnd, EM_CANREDO, 0, 0)) {
fail("TestEditMessages: EM_CANREDO #2");
return PR_FALSE;
}
if (!::SendMessage(wnd, EM_REDO, 0, 0)) {
fail("TestEditMessages: EM_REDO #1");
return PR_FALSE;
}
mTextArea->GetValue(str);
if (str != mTestString) {
fail("TestEditMessage: EM_REDO #1, failed to execute");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
TS_SELECTION_ACP sel;
HRESULT hr;
sel.acpStart = 0;
sel.acpEnd = testStringLength;
sel.style.ase = TS_AE_END;
sel.style.fInterimChar = FALSE;
hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
if (!(SUCCEEDED(hr))) {
fail("TestEditMessages: SetSelection #1");
return PR_FALSE;
}
::SendMessage(wnd, WM_CUT, 0, 0);
mTextArea->GetValue(str);
if (!str.IsEmpty()) {
fail("TestEditMessages: WM_CUT");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
::SendMessage(wnd, WM_PASTE, 0, 0);
mTextArea->GetValue(str);
if (str != mTestString) {
fail("TestEditMessages: WM_PASTE #1");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
::SendMessage(wnd, WM_PASTE, 0, 0);
mTextArea->GetValue(str);
nsAutoString expectedStr(mTestString);
expectedStr += mTestString;
if (str != expectedStr) {
fail("TestEditMessages: WM_PASTE #2");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
sel.acpStart = 0;
sel.acpEnd = testStringLength;
hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
if (!(SUCCEEDED(hr))) {
fail("TestEditMessages: SetSelection #2");
return PR_FALSE;
}
::SendMessage(wnd, WM_CLEAR, 0, 0);
mTextArea->GetValue(str);
if (str != mTestString) {
fail("TestEditMessages: WM_CLEAR #1");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
sel.acpStart = 4;
sel.acpEnd = testStringLength;
hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
if (!(SUCCEEDED(hr))) {
fail("TestEditMessages: SetSelection #3");
return PR_FALSE;
}
::SendMessage(wnd, WM_COPY, 0, 0);
mTextArea->GetValue(str);
if (str != mTestString) {
fail("TestEditMessages: WM_COPY");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
if (!::SendMessage(wnd, EM_CANPASTE, 0, 0)) {
fail("TestEditMessages: EM_CANPASTE #1");
return PR_FALSE;
}
if (!::SendMessage(wnd, EM_CANPASTE, CF_TEXT, 0)) {
fail("TestEditMessages: EM_CANPASTE #2");
return PR_FALSE;
}
if (!::SendMessage(wnd, EM_CANPASTE, CF_UNICODETEXT, 0)) {
fail("TestEditMessages: EM_CANPASTE #3");
return PR_FALSE;
}
::SendMessage(wnd, WM_PASTE, 0, 0);
mTextArea->GetValue(str);
if (str != mTestString) {
fail("TestEditMessages: WM_PASTE #3");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
sel.acpStart = 4;
sel.acpEnd = testStringLength;
hr = mMgr->GetFocusedStore()->SetSelection(1, &sel);
if (!(SUCCEEDED(hr))) {
fail("TestEditMessages: SetSelection #3");
return PR_FALSE;
}
::SendMessage(wnd, WM_CLEAR, 0, 0);
mTextArea->GetValue(str);
if (str != NS_LITERAL_STRING("This")) {
fail("TestEditMessages: WM_CLEAR #2");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
::SendMessage(wnd, WM_PASTE, 0, 0);
mTextArea->GetValue(str);
if (str != mTestString) {
fail("TestEditMessages: WM_PASTE #4");
printf("Current Str: \"%s\"\n", NS_ConvertUTF16toUTF8(str).get());
return PR_FALSE;
}
return PR_TRUE;
}
PRBool
TestApp::GetWidget(nsIWidget** aWidget)
{
nsCOMPtr<nsIDocShell> docShell;
nsresult rv = mWindow->GetDocShell(getter_AddRefs(docShell));
if (NS_FAILED(rv) || !docShell) {
return PR_FALSE;
}
nsCOMPtr<nsIPresShell> presShell;
rv = docShell->GetPresShell(getter_AddRefs(presShell));
if (NS_FAILED(rv) || !presShell) {
return PR_FALSE;
}
nsCOMPtr<nsIViewManager> viewManager = presShell->GetViewManager();
if (!viewManager) {
return PR_FALSE;
}
rv = viewManager->GetRootWidget(aWidget);
return (NS_SUCCEEDED(rv) && aWidget);
}
nsresult
TestApp::GetSelCon(nsISelectionController** aSelCon)
{