/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is XMLterm. * * The Initial Developer of the Original Code is * Ramalingam Saravanan. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // mozXMLTermListeners.cpp: implementation of classes in mozXMLTermListeners.h #include "nsIServiceManager.h" #include "mozXMLT.h" #include "mozXMLTermUtils.h" #include "mozXMLTermListeners.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMMouseEvent.h" #include "nsIDOMNSUIEvent.h" #include "nsIPrivateTextEvent.h" #include "nsIPresShell.h" #include "nsISelectionController.h" ///////////////////////////////////////////////////////////////////////// // mozXMLTermKeyListener factory ///////////////////////////////////////////////////////////////////////// nsresult NS_NewXMLTermKeyListener(nsIDOMEventListener ** aInstancePtrResult, mozIXMLTerminal *aXMLTerminal) { mozXMLTermKeyListener* listener = new mozXMLTermKeyListener(); if (listener == nsnull) { return NS_ERROR_OUT_OF_MEMORY; } // Save non-owning reference to embedding XMLTerminal object listener->SetXMLTerminal(aXMLTerminal); return listener->QueryInterface(NS_GET_IID(nsIDOMEventListener), (void **) aInstancePtrResult); } nsresult NS_NewXMLTermTextListener(nsIDOMEventListener ** aInstancePtrResult, mozIXMLTerminal *aXMLTerminal) { mozXMLTermTextListener* listener = new mozXMLTermTextListener(); if (listener == nsnull) { return NS_ERROR_OUT_OF_MEMORY; } // Save non-owning reference to embedding XMLTerminal object listener->SetXMLTerminal(aXMLTerminal); return listener->QueryInterface(NS_GET_IID(nsIDOMEventListener), (void **) aInstancePtrResult); } nsresult NS_NewXMLTermMouseListener(nsIDOMEventListener ** aInstancePtrResult, mozIXMLTerminal *aXMLTerminal) { mozXMLTermMouseListener* listener = new mozXMLTermMouseListener(); if (listener == nsnull) { return NS_ERROR_OUT_OF_MEMORY; } // Save non-owning reference to embedding XMLTerminal object listener->SetXMLTerminal(aXMLTerminal); return listener->QueryInterface(NS_GET_IID(nsIDOMEventListener), (void **) aInstancePtrResult); } nsresult NS_NewXMLTermDragListener(nsIDOMEventListener ** aInstancePtrResult, mozIXMLTerminal *aXMLTerminal) { mozXMLTermDragListener* listener = new mozXMLTermDragListener(); if (listener == nsnull) { return NS_ERROR_OUT_OF_MEMORY; } // Save non-owning reference to embedding XMLTerminal object listener->SetXMLTerminal(aXMLTerminal); return listener->QueryInterface(NS_GET_IID(nsIDOMEventListener), (void **) aInstancePtrResult); } ///////////////////////////////////////////////////////////////////////// // mozXMLTermKeyListener implementation ///////////////////////////////////////////////////////////////////////// mozXMLTermKeyListener::mozXMLTermKeyListener() : mXMLTerminal(nsnull), mSuspend(PR_FALSE) { } mozXMLTermKeyListener::~mozXMLTermKeyListener() { } NS_IMPL_ADDREF(mozXMLTermKeyListener) NS_IMPL_RELEASE(mozXMLTermKeyListener) NS_IMETHODIMP mozXMLTermKeyListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (aInstancePtr == NULL) { return NS_ERROR_NULL_POINTER; } // Always NULL result, in case of failure *aInstancePtr = NULL; if (aIID.Equals(NS_GET_IID(nsISupports))) { *aInstancePtr = NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(nsIDOMKeyListener*,this)); } else if (aIID.Equals(NS_GET_IID(nsIDOMEventListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMEventListener*,this); } else if (aIID.Equals(NS_GET_IID(nsIDOMKeyListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMKeyListener*,this); } else if (aIID.Equals(NS_GET_IID(mozIXMLTermSuspend))) { *aInstancePtr = NS_STATIC_CAST(mozIXMLTermSuspend*,this); } else { return NS_ERROR_NO_INTERFACE; } NS_ADDREF_THIS(); return NS_OK; } NS_IMETHODIMP mozXMLTermKeyListener::GetSuspend(PRBool* aSuspend) { if (!*aSuspend) return NS_ERROR_NULL_POINTER; *aSuspend = mSuspend; return NS_OK; } NS_IMETHODIMP mozXMLTermKeyListener::SetSuspend(const PRBool aSuspend) { XMLT_LOG(mozXMLTermKeyListener::SetSuspend,50,("aSuspend=0x%x\n", aSuspend)); mSuspend = aSuspend; return NS_OK; } // Individual key handlers return NS_OK to indicate NOT consumed // by default, an error is returned indicating event is consumed NS_IMETHODIMP mozXMLTermKeyListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } // Process KeyDown events (handles control/alt modified key events) NS_IMETHODIMP mozXMLTermKeyListener::KeyDown(nsIDOMEvent* aKeyEvent) { nsCOMPtr keyEvent; keyEvent = do_QueryInterface(aKeyEvent); if (!keyEvent) { // Non-key event passed to keydown, do not consume it return NS_OK; } PRBool shiftKey, ctrlKey, altKey; PRUint32 keyCode; XMLT_LOG(mozXMLTermKeyListener::KeyDown,50,("mSuspend=0x%x\n", mSuspend)); if (NS_SUCCEEDED(keyEvent->GetKeyCode(&keyCode)) && NS_SUCCEEDED(keyEvent->GetShiftKey(&shiftKey)) && NS_SUCCEEDED(keyEvent->GetCtrlKey(&ctrlKey)) && NS_SUCCEEDED(keyEvent->GetAltKey(&altKey)) ) { XMLT_LOG(mozXMLTermKeyListener::KeyDown,52, ("code=0x%x, shift=%d, ctrl=%d, alt=%d\n", keyCode, shiftKey, ctrlKey, altKey)); } // Consume key down event return NS_ERROR_BASE; } NS_IMETHODIMP mozXMLTermKeyListener::KeyUp(nsIDOMEvent* aKeyEvent) { return NS_OK; } // Handle KeyPress events (non control/alt modified key events) NS_IMETHODIMP mozXMLTermKeyListener::KeyPress(nsIDOMEvent* aKeyEvent) { nsresult result; XMLT_LOG(mozXMLTermKeyListener::KeyPress,50,("mSuspend=0x%x\n", mSuspend)); nsCOMPtr keyEvent; keyEvent = do_QueryInterface(aKeyEvent); if (!keyEvent) { // Non-key event passed to keydown, do not consume it return NS_OK; } #if 0 // Debugging nsCOMPtr presShell; result = mXMLTerminal->GetPresShell(getter_AddRefs(presShell)); if (NS_SUCCEEDED(result) && presShell) { nsCOMPtr selection; result = presShell->GetSelection(SELECTION_NORMAL, getter_AddRefs(selection)); if (NS_SUCCEEDED(result) && selection) { nsCOMPtr childNode, parentNode; result = selection->GetFocusNode(getter_AddRefs(childNode)); if (NS_SUCCEEDED(result) && childNode) { PRInt32 j; nsAutoString nodeName; for (j=0; (j<6) && childNode; j++) { result = childNode->GetParentNode(getter_AddRefs(parentNode)); if (NS_SUCCEEDED(result) && parentNode) { result = parentNode->GetNodeName(nodeName); if (NS_SUCCEEDED(result)) { NS_ConvertUTF16toUTF8 CNodeName(nodeName); XMLT_LOG(mozXMLTermKeyListener::KeyPress,58,("nodeName=%s\n", CNodeName.get())); } childNode = parentNode; } else { childNode = nsnull; } } } } } #endif PRUint32 keyCode; PRBool shiftKey, ctrlKey, altKey; if (NS_SUCCEEDED(keyEvent->GetKeyCode(&keyCode)) && NS_SUCCEEDED(keyEvent->GetShiftKey(&shiftKey)) && NS_SUCCEEDED(keyEvent->GetCtrlKey(&ctrlKey)) && NS_SUCCEEDED(keyEvent->GetAltKey(&altKey)) ) { PRUint32 keyChar = 0; PRUint32 escPrefix = 0; nsAutoString JSCommand; JSCommand.SetLength(0); PRBool screenMode = 0; result = mXMLTerminal->GetScreenMode(&screenMode); result = keyEvent->GetCharCode(&keyChar); XMLT_LOG(mozXMLTermKeyListener::KeyPress,52, ("code=0x%x, char=0x%x, shift=%d, ctrl=%d, alt=%d, screenMode=%d\n", keyCode, keyChar, shiftKey, ctrlKey, altKey, screenMode)); if (keyChar == 0) { // Key that hasn't been mapped to a character code switch (keyCode) { case nsIDOMKeyEvent::DOM_VK_SHIFT: case nsIDOMKeyEvent::DOM_VK_CONTROL: case nsIDOMKeyEvent::DOM_VK_ALT: break; // ignore modifier key event case nsIDOMKeyEvent::DOM_VK_BACK_SPACE: keyChar = U_BACKSPACE; break; case nsIDOMKeyEvent::DOM_VK_DELETE: keyChar = U_DEL; break; case nsIDOMKeyEvent::DOM_VK_TAB: keyChar = U_TAB; break; case nsIDOMKeyEvent::DOM_VK_RETURN: keyChar = U_CRETURN; break; case nsIDOMKeyEvent::DOM_VK_UP: escPrefix = 1; keyChar = U_A_CHAR; break; case nsIDOMKeyEvent::DOM_VK_DOWN: escPrefix = 1; keyChar = U_B_CHAR; break; case nsIDOMKeyEvent::DOM_VK_RIGHT: escPrefix = 1; keyChar = U_C_CHAR; break; case nsIDOMKeyEvent::DOM_VK_LEFT: escPrefix = 1; keyChar = U_D_CHAR; break; case nsIDOMKeyEvent::DOM_VK_ESCAPE: keyChar = U_ESCAPE; break; case nsIDOMKeyEvent::DOM_VK_HOME: JSCommand.AssignLiteral("ScrollHomeKey"); break; case nsIDOMKeyEvent::DOM_VK_END: JSCommand.AssignLiteral("ScrollEndKey"); break; case nsIDOMKeyEvent::DOM_VK_PAGE_UP: JSCommand.AssignLiteral("ScrollPageUpKey"); break; case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN: JSCommand.AssignLiteral("ScrollPageDownKey"); break; case nsIDOMKeyEvent::DOM_VK_F1: JSCommand.AssignLiteral("F1Key"); break; case nsIDOMKeyEvent::DOM_VK_F2: JSCommand.AssignLiteral("F2Key"); break; case nsIDOMKeyEvent::DOM_VK_F3: JSCommand.AssignLiteral("F3Key"); break; case nsIDOMKeyEvent::DOM_VK_F4: JSCommand.AssignLiteral("F4Key"); break; case nsIDOMKeyEvent::DOM_VK_F5: JSCommand.AssignLiteral("F5Key"); break; case nsIDOMKeyEvent::DOM_VK_F6: JSCommand.AssignLiteral("F6Key"); break; case nsIDOMKeyEvent::DOM_VK_F7: JSCommand.AssignLiteral("F7Key"); break; case nsIDOMKeyEvent::DOM_VK_F8: JSCommand.AssignLiteral("F8Key"); break; case nsIDOMKeyEvent::DOM_VK_F9: JSCommand.AssignLiteral("F9Key"); break; default: if ( (ctrlKey && (keyCode ==nsIDOMKeyEvent::DOM_VK_SPACE)) || (ctrlKey && shiftKey && (keyCode ==nsIDOMKeyEvent::DOM_VK_2)) ) { // Hack to handle input of NUL characters in NUL-terminated strings // See also: mozLineTerm::Write keyChar = U_PRIVATE0; } else { // ignore event without consuming return NS_OK; } } } else if ((ctrlKey == PR_TRUE) && (altKey == PR_FALSE) && (keyChar >= 0x40U) && (keyChar < 0x80U)) { // Control character, without Alt; adjust character code // Is this portable? keyChar = (keyChar >= 0x60U) ? keyChar-0x60U : keyChar-0x40U; } XMLT_LOG(mozXMLTermKeyListener::KeyPress,53, ("escPrefix=%d, keyChar=0x%x, \n", escPrefix, keyChar)); if (!JSCommand.IsEmpty()) { // Execute JS command nsCOMPtr domDocument; result = mXMLTerminal->GetDocument(getter_AddRefs(domDocument)); if (NS_SUCCEEDED(result) && domDocument) { nsAutoString JSInput = JSCommand; nsAutoString JSOutput; JSOutput.SetLength(0); JSInput.AppendLiteral("("); JSInput.AppendInt(shiftKey,10); JSInput.AppendLiteral(","); JSInput.AppendInt(ctrlKey,10); JSInput.Append(NS_LITERAL_STRING(");")); result = mozXMLTermUtils::ExecuteScript(domDocument, JSInput, JSOutput); } } if (!mSuspend && (keyChar > 0) && (keyChar <= 0xFFFDU)) { // Transmit valid non-null Unicode character nsAutoString keyString; keyString.SetLength(0); if (escPrefix) { keyString.Append((PRUnichar) U_ESCAPE); keyString.Append((PRUnichar) U_LBRACKET); } keyString.Append((PRUnichar) keyChar); result = mXMLTerminal->SendTextAux(keyString.get()); } } // Consume key press event return NS_ERROR_BASE; } ///////////////////////////////////////////////////////////////////////// // mozXMLTermTextListener implementation ///////////////////////////////////////////////////////////////////////// mozXMLTermTextListener::mozXMLTermTextListener() { } mozXMLTermTextListener::~mozXMLTermTextListener() { } NS_IMPL_ADDREF(mozXMLTermTextListener) NS_IMPL_RELEASE(mozXMLTermTextListener) NS_IMETHODIMP mozXMLTermTextListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (aInstancePtr == NULL) { return NS_ERROR_NULL_POINTER; } // Always NULL result, in case of failure *aInstancePtr = NULL; if (aIID.Equals(NS_GET_IID(nsISupports))) { *aInstancePtr = NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(nsIDOMTextListener*,this)); } else if (aIID.Equals(NS_GET_IID(nsIDOMEventListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMEventListener*,this); } else if (aIID.Equals(NS_GET_IID(nsIDOMTextListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMTextListener*,this); } else { return NS_ERROR_NO_INTERFACE; } NS_ADDREF_THIS(); return NS_OK; } NS_IMETHODIMP mozXMLTermTextListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermTextListener::HandleText(nsIDOMEvent* aTextEvent) { nsCOMPtr textEvent (do_QueryInterface(aTextEvent)); if (!textEvent) { // Soft failure return NS_OK; } XMLT_LOG(mozXMLTermTextListener::HandleText,50,("\n")); nsAutoString textStr; textEvent->GetText(textStr); // Transmit text to terminal mXMLTerminal->SendTextAux(textStr.get()); return NS_OK; } ///////////////////////////////////////////////////////////////////////// // mozXMLTermMouseListener implementation ///////////////////////////////////////////////////////////////////////// mozXMLTermMouseListener::mozXMLTermMouseListener() { } mozXMLTermMouseListener::~mozXMLTermMouseListener() { } NS_IMPL_ADDREF(mozXMLTermMouseListener) NS_IMPL_RELEASE(mozXMLTermMouseListener) NS_IMETHODIMP mozXMLTermMouseListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (aInstancePtr == NULL) { return NS_ERROR_NULL_POINTER; } // Always NULL result, in case of failure *aInstancePtr = NULL; if (aIID.Equals(NS_GET_IID(nsISupports))) { *aInstancePtr = NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(nsIDOMMouseListener*,this)); } else if (aIID.Equals(NS_GET_IID(nsIDOMEventListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMEventListener*,this); } else if (aIID.Equals(NS_GET_IID(nsIDOMMouseListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMMouseListener*,this); } else { return NS_ERROR_NO_INTERFACE; } NS_ADDREF_THIS(); return NS_OK; } NS_IMETHODIMP mozXMLTermMouseListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) { if (!aMouseEvent) return NS_OK; nsCOMPtr mouseEvent; mouseEvent = do_QueryInterface(aMouseEvent); if (!mouseEvent) { // Non-mouse event passed; do not consume it return NS_OK; } PRUint16 buttonCode = (PRUint16)-1; mouseEvent->GetButton(&buttonCode); XMLT_LOG(mozXMLTermMouseListener::MouseDown,50,("buttonCode=%d\n", buttonCode)); if (buttonCode == 1) { // Middle-mouse button pressed; initiate paste mXMLTerminal->Paste(); } return NS_OK; } NS_IMETHODIMP mozXMLTermMouseListener::MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermMouseListener::MouseClick(nsIDOMEvent* aMouseEvent) { nsresult result; if (!aMouseEvent) return NS_OK; nsCOMPtr mouseEvent; mouseEvent = do_QueryInterface(aMouseEvent); if (!mouseEvent) { // Non-mouse event passed; do not consume it return NS_OK; } PRUint16 buttonCode = (PRUint16)-1; mouseEvent->GetButton(&buttonCode); PRInt32 screenX, screenY; result = mouseEvent->GetScreenX(&screenX); result = mouseEvent->GetScreenY(&screenY); XMLT_LOG(mozXMLTermMouseListener::MouseClick,50, ("buttonCode=%d\n", buttonCode)); #if 0 // NO MORE NEED FOR THIS WORKAROUND! // Without this workaround, clicking on the xmlterm window to give it // focus fails position the cursor at the end of the last line // (For some reason, the MouseDown event causes the cursor to be positioned // in the line above the location of the mouse click // Get selection nsCOMPtr presShell; result = mXMLTerminal->GetPresShell(getter_AddRefs(presShell)); if (NS_FAILED(result) || !presShell) return NS_OK; // Do not consume mouse event nsCOMPtr selCon; selCon = do_QueryInterface(presShell); if (!selCon) return NS_ERROR_FAILURE; nsCOMPtr selection; result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); if (NS_FAILED(result) || !selection) return NS_OK; // Do not consume mouse event PRBool isCollapsed; result = selection->GetIsCollapsed(&isCollapsed); if (NS_FAILED(result)) return NS_OK; // Do not consume mouse event XMLT_LOG(mozXMLTermMouseListener::MouseClick,50, ("isCollapsed=%d\n", isCollapsed)); // If non-collapsed selection, do not collapse it if (!isCollapsed) return NS_OK; // Locate selection range nsCOMPtr uiEvent (do_QueryInterface(mouseEvent)); if (!uiEvent) return NS_OK; // Do not consume mouse event nsCOMPtr parentNode; result = uiEvent->GetRangeParent(getter_AddRefs(parentNode)); if (NS_FAILED(result) || !parentNode) return NS_OK; // Do not consume mouse event PRInt32 offset = 0; result = uiEvent->GetRangeOffset(&offset); if (NS_FAILED(result)) return NS_OK; // Do not consume mouse event (void)selection->Collapse(parentNode, offset); #endif return NS_OK; // Do not consume mouse event } NS_IMETHODIMP mozXMLTermMouseListener::MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermMouseListener::MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermMouseListener::MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; } ///////////////////////////////////////////////////////////////////////// // mozXMLTermDragListener implementation ///////////////////////////////////////////////////////////////////////// mozXMLTermDragListener::mozXMLTermDragListener() { } mozXMLTermDragListener::~mozXMLTermDragListener() { } NS_IMPL_ADDREF(mozXMLTermDragListener) NS_IMPL_RELEASE(mozXMLTermDragListener) NS_IMETHODIMP mozXMLTermDragListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (aInstancePtr == NULL) { return NS_ERROR_NULL_POINTER; } // Always NULL result, in case of failure *aInstancePtr = NULL; if (aIID.Equals(NS_GET_IID(nsISupports))) { *aInstancePtr = NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(nsIDOMDragListener*,this)); } else if (aIID.Equals(NS_GET_IID(nsIDOMEventListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMEventListener*,this); } else if (aIID.Equals(NS_GET_IID(nsIDOMDragListener))) { *aInstancePtr = NS_STATIC_CAST(nsIDOMDragListener*,this); } else { return NS_ERROR_NO_INTERFACE; } NS_ADDREF_THIS(); return NS_OK; } NS_IMETHODIMP mozXMLTermDragListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermDragListener::DragEnter(nsIDOMEvent* aDragEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermDragListener::DragOver(nsIDOMEvent* aDragEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermDragListener::DragExit(nsIDOMEvent* aDragEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermDragListener::DragDrop(nsIDOMEvent* aDragEvent) { return NS_OK; } NS_IMETHODIMP mozXMLTermDragListener::DragGesture(nsIDOMEvent* aDragEvent) { return NS_OK; }