зеркало из https://github.com/mozilla/pjs.git
Add support for native keybindings for input and textarea for gtk2. This allows us to respect the GTK keybinding preferences. Bug 257405, r=blizzard, sr=roc.
This commit is contained in:
Родитель
b89a09b444
Коммит
d342e8f7b4
|
@ -299,6 +299,7 @@ content/xbl/Makefile
|
|||
content/xbl/public/Makefile
|
||||
content/xbl/src/Makefile
|
||||
content/xbl/builtin/Makefile
|
||||
content/xbl/builtin/gtk2/Makefile
|
||||
content/xbl/builtin/unix/Makefile
|
||||
content/xbl/builtin/win/Makefile
|
||||
content/xsl/Makefile
|
||||
|
|
|
@ -48,9 +48,13 @@ else
|
|||
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
DIRS = mac
|
||||
else
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
|
||||
DIRS = gtk2
|
||||
else
|
||||
DIRS = unix
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Makefile
|
|
@ -0,0 +1,110 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<bindings id="htmlBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="inputFields">
|
||||
<handlers>
|
||||
<handler event="keypress" key="a" modifiers="alt"
|
||||
command="cmd_selectAll"/>
|
||||
<handler event="keypress" key="y" modifiers="accel"
|
||||
command="cmd_redo"/>
|
||||
<handler event="keypress" key="z" modifiers="accel,shift" command="cmd_redo"/>
|
||||
<handler event="keypress" key="z" modifiers="accel" command="cmd_undo"/>
|
||||
<handler event="keypress" keycode="VK_F14" command="cmd_undo" />
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="textAreas">
|
||||
<handlers>
|
||||
<handler event="keypress" key="a" modifiers="alt"
|
||||
command="cmd_selectAll"/>
|
||||
<handler event="keypress" key="y" modifiers="accel"
|
||||
command="cmd_redo"/>
|
||||
<handler event="keypress" key="z" modifiers="accel" command="cmd_undo"/>
|
||||
<handler event="keypress" key="z" modifiers="accel,shift" command="cmd_redo"/>
|
||||
<handler event="keypress" keycode="VK_F20" command="cmd_cut" />
|
||||
<handler event="keypress" keycode="VK_F16" command="cmd_copy" />
|
||||
<handler event="keypress" keycode="VK_F18" command="cmd_paste" />
|
||||
<handler event="keypress" keycode="VK_F14" command="cmd_undo" />
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="browser">
|
||||
<handlers>
|
||||
<handler event="keypress" keycode="VK_PAGE_UP" command="cmd_movePageUp"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_DOWN" command="cmd_movePageDown"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_UP" modifiers="shift" command="cmd_selectPageUp"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="shift" command="cmd_selectPageDown"/>
|
||||
|
||||
<handler event="keypress" keycode="VK_DELETE" modifiers="shift" command="cmd_cut" />
|
||||
<handler event="keypress" keycode="VK_DELETE" modifiers="control" command="cmd_copy" />
|
||||
<handler event="keypress" keycode="VK_INSERT" modifiers="control" command="cmd_copy" />
|
||||
<handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop" />
|
||||
<handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom" />
|
||||
<handler event="keypress" keycode="VK_F20" command="cmd_cut" />
|
||||
<handler event="keypress" keycode="VK_F16" command="cmd_copy" />
|
||||
<handler event="keypress" keycode="VK_F18" command="cmd_paste" />
|
||||
<handler event="keypress" keycode="VK_F14" command="cmd_undo" />
|
||||
<handler event="keypress" keycode="VK_LEFT" modifiers="control" command="cmd_wordPrevious" />
|
||||
<handler event="keypress" keycode="VK_RIGHT" modifiers="control" command="cmd_wordNext" />
|
||||
<handler event="keypress" keycode="VK_LEFT" modifiers="control,shift" command="cmd_selectWordPrevious" />
|
||||
<handler event="keypress" keycode="VK_RIGHT" modifiers="control,shift" command="cmd_selectWordNext" />
|
||||
<handler event="keypress" keycode="VK_LEFT" modifiers="shift" command="cmd_selectCharPrevious" />
|
||||
<handler event="keypress" keycode="VK_RIGHT" modifiers="shift" command="cmd_selectCharNext" />
|
||||
<handler event="keypress" keycode="VK_HOME" modifiers="shift" command="cmd_selectBeginLine" />
|
||||
<handler event="keypress" keycode="VK_END" modifiers="shift" command="cmd_selectEndLine" />
|
||||
<handler event="keypress" keycode="VK_UP" modifiers="shift" command="cmd_selectLinePrevious" />
|
||||
<handler event="keypress" keycode="VK_DOWN" modifiers="shift" command="cmd_selectLineNext" />
|
||||
<handler event="keypress" key="a" modifiers="alt" command="cmd_selectAll"/>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="editor">
|
||||
<handlers>
|
||||
<handler event="keypress" key="h" modifiers="control" command="cmd_deleteCharBackward"/>
|
||||
<handler event="keypress" key="d" modifiers="control" command="cmd_deleteCharForward"/>
|
||||
<handler event="keypress" key="k" modifiers="control" command="cmd_deleteToEndOfLine"/>
|
||||
<handler event="keypress" key="u" modifiers="control" command="cmd_deleteToBeginningOfLine"/>
|
||||
<handler event="keypress" key="a" modifiers="control" command="cmd_beginLine"/>
|
||||
<handler event="keypress" key="e" modifiers="control" command="cmd_endLine"/>
|
||||
<handler event="keypress" key="b" modifiers="control" command="cmd_charPrevious"/>
|
||||
<handler event="keypress" key="f" modifiers="control" command="cmd_charNext"/>
|
||||
<handler event="keypress" key="p" modifiers="control" command="cmd_linePrevious"/>
|
||||
<handler event="keypress" key="n" modifiers="control" command="cmd_lineNext"/>
|
||||
<handler event="keypress" key="x" modifiers="control" command="cmd_cut"/>
|
||||
<handler event="keypress" key="c" modifiers="control" command="cmd_copy"/>
|
||||
<handler event="keypress" key="v" modifiers="control" command="cmd_paste"/>
|
||||
<handler event="keypress" key="z" modifiers="control" command="cmd_undo"/>
|
||||
<handler event="keypress" key="r" modifiers="accel" command="cmd_redo"/>
|
||||
<handler event="keypress" key="y" modifiers="accel" command="cmd_redo"/>
|
||||
<handler event="keypress" key="a" modifiers="alt" command="cmd_selectAll"/>
|
||||
<handler event="keypress" keycode="VK_DELETE" modifiers="shift" command="cmd_cutOrDelete"/>
|
||||
<handler event="keypress" keycode="VK_DELETE" modifiers="control" command="cmd_copyOrDelete"/>
|
||||
<handler event="keypress" keycode="VK_INSERT" modifiers="control" command="cmd_copy"/>
|
||||
<handler event="keypress" keycode="VK_INSERT" modifiers="shift" command="cmd_paste"/>
|
||||
<handler event="keypress" keycode="VK_LEFT" modifiers="control" command="cmd_wordPrevious"/>
|
||||
<handler event="keypress" keycode="VK_RIGHT" modifiers="control" command="cmd_wordNext"/>
|
||||
<handler event="keypress" keycode="VK_LEFT" modifiers="shift,control" command="cmd_selectWordPrevious"/>
|
||||
<handler event="keypress" keycode="VK_RIGHT" modifiers="shift,control" command="cmd_selectWordNext"/>
|
||||
<handler event="keypress" keycode="VK_BACK" modifiers="control" command="cmd_deleteWordBackward"/>
|
||||
<handler event="keypress" keycode="VK_HOME" command="cmd_beginLine"/>
|
||||
<handler event="keypress" keycode="VK_END" command="cmd_endLine"/>
|
||||
<handler event="keypress" keycode="VK_HOME" modifiers="shift" command="cmd_selectBeginLine"/>
|
||||
<handler event="keypress" keycode="VK_END" modifiers="shift" command="cmd_selectEndLine"/>
|
||||
<handler event="keypress" keycode="VK_HOME" modifiers="shift,control" command="cmd_selectTop"/>
|
||||
<handler event="keypress" keycode="VK_END" modifiers="shift,control" command="cmd_selectBottom"/>
|
||||
<handler event="keypress" keycode="VK_HOME" modifiers="control" command="cmd_moveTop"/>
|
||||
<handler event="keypress" keycode="VK_END" modifiers="control" command="cmd_moveBottom"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_UP" command="cmd_movePageUp"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_DOWN" command="cmd_movePageDown"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_UP" modifiers="shift" command="cmd_selectPageUp"/>
|
||||
<handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="shift" command="cmd_selectPageDown"/>
|
||||
<handler event="keypress" keycode="VK_F20" command="cmd_cut" />
|
||||
<handler event="keypress" keycode="VK_F16" command="cmd_copy" />
|
||||
<handler event="keypress" keycode="VK_F18" command="cmd_paste" />
|
||||
<handler event="keypress" keycode="VK_F14" command="cmd_undo" />
|
||||
</handlers>
|
||||
</binding>
|
||||
</bindings>
|
|
@ -128,6 +128,7 @@
|
|||
#include "nsStyleSet.h"
|
||||
#include "nsImageFrame.h"
|
||||
#include "nsILanguageAtomService.h"
|
||||
#include "nsTextControlFrame.h"
|
||||
|
||||
// view stuff
|
||||
#include "nsViewsCID.h"
|
||||
|
@ -417,6 +418,7 @@ Shutdown()
|
|||
|
||||
GlobalWindowImpl::ShutDown();
|
||||
nsDOMClassInfo::ShutDown();
|
||||
nsTextControlFrame::ShutDown();
|
||||
}
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
|
|
|
@ -120,6 +120,10 @@
|
|||
#include "nsIDOMText.h" //for multiline getselection
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsIDOMEventGroup.h"
|
||||
#include "nsIDOM3EventTarget.h"
|
||||
#include "nsINativeKeyBindings.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsIBidiKeyboard.h"
|
||||
|
@ -138,8 +142,12 @@ static const PRInt32 DEFAULT_COLS = 20;
|
|||
static const PRInt32 DEFAULT_ROWS = 1;
|
||||
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
|
||||
|
||||
static nsINativeKeyBindings *sNativeInputBindings = nsnull;
|
||||
static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
|
||||
|
||||
class nsTextInputListener : public nsISelectionListener,
|
||||
public nsIDOMFocusListener,
|
||||
public nsIDOMKeyListener,
|
||||
public nsIEditorObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
|
@ -169,12 +177,19 @@ public:
|
|||
NS_IMETHOD Blur (nsIDOMEvent* aEvent);
|
||||
/* END interfaces from nsIDOMFocusListener*/
|
||||
|
||||
// nsIDOMKeyListener
|
||||
NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
|
||||
NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
|
||||
NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
|
||||
|
||||
NS_DECL_NSIEDITOROBSERVER
|
||||
|
||||
protected:
|
||||
|
||||
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
|
||||
|
||||
NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
|
||||
|
||||
protected:
|
||||
|
||||
nsTextControlFrame* mFrame; // weak reference
|
||||
|
@ -211,9 +226,18 @@ nsTextInputListener::~nsTextInputListener()
|
|||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS5(nsTextInputListener, nsISelectionListener,
|
||||
nsIDOMEventListener, nsIDOMFocusListener,
|
||||
nsIEditorObserver, nsISupportsWeakReference)
|
||||
NS_IMPL_ADDREF(nsTextInputListener)
|
||||
NS_IMPL_RELEASE(nsTextInputListener)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsTextInputListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIEditorObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMFocusListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFocusListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// BEGIN nsIDOMSelectionListener
|
||||
|
||||
|
@ -313,6 +337,103 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent)
|
|||
|
||||
// END nsIFocusListener
|
||||
|
||||
// BEGIN nsIDOMKeyListener
|
||||
|
||||
static void
|
||||
DoCommandCallback(const char *aCommand, void *aData)
|
||||
{
|
||||
nsTextControlFrame *frame = NS_STATIC_CAST(nsTextControlFrame*, aData);
|
||||
nsIContent *content = frame->GetContent();
|
||||
|
||||
nsCOMPtr<nsIControllers> controllers;
|
||||
nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(content);
|
||||
if (input) {
|
||||
input->GetControllers(getter_AddRefs(controllers));
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea =
|
||||
do_QueryInterface(content);
|
||||
|
||||
if (textArea) {
|
||||
textArea->GetControllers(getter_AddRefs(controllers));
|
||||
}
|
||||
}
|
||||
|
||||
if (!controllers) {
|
||||
NS_WARNING("Could not get controllers");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIController> controller;
|
||||
controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
|
||||
if (controller) {
|
||||
controller->DoCommand(aCommand);
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool
|
||||
DOMEventToNativeKeyEvent(nsIDOMEvent *aDOMEvent,
|
||||
nsNativeKeyEvent *aNativeEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSUIEvent> nsevent = do_QueryInterface(aDOMEvent);
|
||||
PRBool defaultPrevented;
|
||||
nsevent->GetPreventDefault(&defaultPrevented);
|
||||
if (defaultPrevented)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aDOMEvent);
|
||||
|
||||
keyEvent->GetCharCode(&aNativeEvent->charCode);
|
||||
keyEvent->GetKeyCode(&aNativeEvent->keyCode);
|
||||
keyEvent->GetAltKey(&aNativeEvent->altKey);
|
||||
keyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
|
||||
keyEvent->GetShiftKey(&aNativeEvent->shiftKey);
|
||||
keyEvent->GetMetaKey(&aNativeEvent->metaKey);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyDown(nsIDOMEvent *aKeyEvent)
|
||||
{
|
||||
nsNativeKeyEvent nativeEvent;
|
||||
nsINativeKeyBindings *bindings = GetKeyBindings();
|
||||
if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
|
||||
if (bindings->KeyDown(nativeEvent, DoCommandCallback, mFrame)) {
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyPress(nsIDOMEvent *aKeyEvent)
|
||||
{
|
||||
nsNativeKeyEvent nativeEvent;
|
||||
nsINativeKeyBindings *bindings = GetKeyBindings();
|
||||
if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
|
||||
if (bindings->KeyPress(nativeEvent, DoCommandCallback, mFrame)) {
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyUp(nsIDOMEvent *aKeyEvent)
|
||||
{
|
||||
nsNativeKeyEvent nativeEvent;
|
||||
nsINativeKeyBindings *bindings = GetKeyBindings();
|
||||
if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
|
||||
if (bindings->KeyUp(nativeEvent, DoCommandCallback, mFrame)) {
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
// END nsIDOMKeyListener
|
||||
|
||||
// BEGIN nsIEditorObserver
|
||||
|
||||
|
@ -371,6 +492,36 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
|
|||
return domWindow->UpdateCommands(commandsToUpdate);
|
||||
}
|
||||
|
||||
nsINativeKeyBindings*
|
||||
nsTextInputListener::GetKeyBindings()
|
||||
{
|
||||
if (mFrame->IsTextArea()) {
|
||||
static PRBool sNoTextAreaBindings = PR_FALSE;
|
||||
|
||||
if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
|
||||
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
|
||||
&sNativeTextAreaBindings);
|
||||
|
||||
if (!sNativeTextAreaBindings) {
|
||||
sNoTextAreaBindings = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return sNativeTextAreaBindings;
|
||||
}
|
||||
|
||||
static PRBool sNoInputBindings = PR_FALSE;
|
||||
if (!sNativeInputBindings && !sNoInputBindings) {
|
||||
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
|
||||
&sNativeInputBindings);
|
||||
|
||||
if (!sNativeInputBindings) {
|
||||
sNoInputBindings = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return sNativeInputBindings;
|
||||
}
|
||||
|
||||
// END nsTextInputListener
|
||||
|
||||
|
@ -1255,6 +1406,22 @@ nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
|
|||
{
|
||||
erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
||||
erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
|
||||
nsCOMPtr<nsIDOM3EventTarget> dom3Targ = do_QueryInterface(mContent);
|
||||
if (dom3Targ) {
|
||||
// cast because of ambiguous base
|
||||
nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
|
||||
mTextListener);
|
||||
|
||||
dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
}
|
||||
}
|
||||
|
||||
mDidPreDestroy = PR_TRUE;
|
||||
|
@ -3005,11 +3172,10 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
|
|||
scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
//register keylistener
|
||||
nsCOMPtr<nsIDOMEventReceiver> erP;
|
||||
if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP))) && erP)
|
||||
{
|
||||
// register the event listeners with the DOM event reveiver
|
||||
//register focus and key listeners
|
||||
nsCOMPtr<nsIDOMEventReceiver> erP = do_QueryInterface(mContent);
|
||||
if (erP) {
|
||||
// register the event listeners with the DOM event receiver
|
||||
rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
|
||||
// XXXbryner do we need to check for a null presshell here?
|
||||
|
@ -3017,6 +3183,22 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
||||
erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
|
||||
nsCOMPtr<nsIDOM3EventTarget> dom3Targ = do_QueryInterface(mContent);
|
||||
if (dom3Targ) {
|
||||
// cast because of ambiguous base
|
||||
nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
|
||||
mTextListener);
|
||||
|
||||
dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keydown"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keyup"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
}
|
||||
|
||||
while(first)
|
||||
{
|
||||
nsIView *view = first->GetView();
|
||||
|
@ -3105,3 +3287,10 @@ nsTextControlFrame::HandleEvent(nsPresContext* aPresContext,
|
|||
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsTextControlFrame::ShutDown()
|
||||
{
|
||||
NS_IF_RELEASE(sNativeTextAreaBindings);
|
||||
NS_IF_RELEASE(sNativeInputBindings);
|
||||
}
|
||||
|
|
|
@ -212,6 +212,9 @@ public: //for methods who access nsTextControlFrame directly
|
|||
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
|
||||
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
|
||||
|
||||
/* called to free up native keybinding services */
|
||||
static NS_HIDDEN_(void) ShutDown();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
|
|
@ -120,6 +120,10 @@
|
|||
#include "nsIDOMText.h" //for multiline getselection
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsIDOMEventGroup.h"
|
||||
#include "nsIDOM3EventTarget.h"
|
||||
#include "nsINativeKeyBindings.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsIBidiKeyboard.h"
|
||||
|
@ -138,8 +142,12 @@ static const PRInt32 DEFAULT_COLS = 20;
|
|||
static const PRInt32 DEFAULT_ROWS = 1;
|
||||
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
|
||||
|
||||
static nsINativeKeyBindings *sNativeInputBindings = nsnull;
|
||||
static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
|
||||
|
||||
class nsTextInputListener : public nsISelectionListener,
|
||||
public nsIDOMFocusListener,
|
||||
public nsIDOMKeyListener,
|
||||
public nsIEditorObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
|
@ -169,12 +177,19 @@ public:
|
|||
NS_IMETHOD Blur (nsIDOMEvent* aEvent);
|
||||
/* END interfaces from nsIDOMFocusListener*/
|
||||
|
||||
// nsIDOMKeyListener
|
||||
NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
|
||||
NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
|
||||
NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
|
||||
|
||||
NS_DECL_NSIEDITOROBSERVER
|
||||
|
||||
protected:
|
||||
|
||||
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
|
||||
|
||||
NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
|
||||
|
||||
protected:
|
||||
|
||||
nsTextControlFrame* mFrame; // weak reference
|
||||
|
@ -211,9 +226,18 @@ nsTextInputListener::~nsTextInputListener()
|
|||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS5(nsTextInputListener, nsISelectionListener,
|
||||
nsIDOMEventListener, nsIDOMFocusListener,
|
||||
nsIEditorObserver, nsISupportsWeakReference)
|
||||
NS_IMPL_ADDREF(nsTextInputListener)
|
||||
NS_IMPL_RELEASE(nsTextInputListener)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsTextInputListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIEditorObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMFocusListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFocusListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// BEGIN nsIDOMSelectionListener
|
||||
|
||||
|
@ -313,6 +337,103 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent)
|
|||
|
||||
// END nsIFocusListener
|
||||
|
||||
// BEGIN nsIDOMKeyListener
|
||||
|
||||
static void
|
||||
DoCommandCallback(const char *aCommand, void *aData)
|
||||
{
|
||||
nsTextControlFrame *frame = NS_STATIC_CAST(nsTextControlFrame*, aData);
|
||||
nsIContent *content = frame->GetContent();
|
||||
|
||||
nsCOMPtr<nsIControllers> controllers;
|
||||
nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(content);
|
||||
if (input) {
|
||||
input->GetControllers(getter_AddRefs(controllers));
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea =
|
||||
do_QueryInterface(content);
|
||||
|
||||
if (textArea) {
|
||||
textArea->GetControllers(getter_AddRefs(controllers));
|
||||
}
|
||||
}
|
||||
|
||||
if (!controllers) {
|
||||
NS_WARNING("Could not get controllers");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIController> controller;
|
||||
controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
|
||||
if (controller) {
|
||||
controller->DoCommand(aCommand);
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool
|
||||
DOMEventToNativeKeyEvent(nsIDOMEvent *aDOMEvent,
|
||||
nsNativeKeyEvent *aNativeEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSUIEvent> nsevent = do_QueryInterface(aDOMEvent);
|
||||
PRBool defaultPrevented;
|
||||
nsevent->GetPreventDefault(&defaultPrevented);
|
||||
if (defaultPrevented)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aDOMEvent);
|
||||
|
||||
keyEvent->GetCharCode(&aNativeEvent->charCode);
|
||||
keyEvent->GetKeyCode(&aNativeEvent->keyCode);
|
||||
keyEvent->GetAltKey(&aNativeEvent->altKey);
|
||||
keyEvent->GetCtrlKey(&aNativeEvent->ctrlKey);
|
||||
keyEvent->GetShiftKey(&aNativeEvent->shiftKey);
|
||||
keyEvent->GetMetaKey(&aNativeEvent->metaKey);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyDown(nsIDOMEvent *aKeyEvent)
|
||||
{
|
||||
nsNativeKeyEvent nativeEvent;
|
||||
nsINativeKeyBindings *bindings = GetKeyBindings();
|
||||
if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
|
||||
if (bindings->KeyDown(nativeEvent, DoCommandCallback, mFrame)) {
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyPress(nsIDOMEvent *aKeyEvent)
|
||||
{
|
||||
nsNativeKeyEvent nativeEvent;
|
||||
nsINativeKeyBindings *bindings = GetKeyBindings();
|
||||
if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
|
||||
if (bindings->KeyPress(nativeEvent, DoCommandCallback, mFrame)) {
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyUp(nsIDOMEvent *aKeyEvent)
|
||||
{
|
||||
nsNativeKeyEvent nativeEvent;
|
||||
nsINativeKeyBindings *bindings = GetKeyBindings();
|
||||
if (bindings && DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent)) {
|
||||
if (bindings->KeyUp(nativeEvent, DoCommandCallback, mFrame)) {
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
// END nsIDOMKeyListener
|
||||
|
||||
// BEGIN nsIEditorObserver
|
||||
|
||||
|
@ -371,6 +492,36 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
|
|||
return domWindow->UpdateCommands(commandsToUpdate);
|
||||
}
|
||||
|
||||
nsINativeKeyBindings*
|
||||
nsTextInputListener::GetKeyBindings()
|
||||
{
|
||||
if (mFrame->IsTextArea()) {
|
||||
static PRBool sNoTextAreaBindings = PR_FALSE;
|
||||
|
||||
if (!sNativeTextAreaBindings && !sNoTextAreaBindings) {
|
||||
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea",
|
||||
&sNativeTextAreaBindings);
|
||||
|
||||
if (!sNativeTextAreaBindings) {
|
||||
sNoTextAreaBindings = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return sNativeTextAreaBindings;
|
||||
}
|
||||
|
||||
static PRBool sNoInputBindings = PR_FALSE;
|
||||
if (!sNativeInputBindings && !sNoInputBindings) {
|
||||
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input",
|
||||
&sNativeInputBindings);
|
||||
|
||||
if (!sNativeInputBindings) {
|
||||
sNoInputBindings = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return sNativeInputBindings;
|
||||
}
|
||||
|
||||
// END nsTextInputListener
|
||||
|
||||
|
@ -1255,6 +1406,22 @@ nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
|
|||
{
|
||||
erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
||||
erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
|
||||
nsCOMPtr<nsIDOM3EventTarget> dom3Targ = do_QueryInterface(mContent);
|
||||
if (dom3Targ) {
|
||||
// cast because of ambiguous base
|
||||
nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
|
||||
mTextListener);
|
||||
|
||||
dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keydown"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keypress"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->RemoveGroupedEventListener(NS_LITERAL_STRING("keyup"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
}
|
||||
}
|
||||
|
||||
mDidPreDestroy = PR_TRUE;
|
||||
|
@ -3005,11 +3172,10 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
|
|||
scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
//register keylistener
|
||||
nsCOMPtr<nsIDOMEventReceiver> erP;
|
||||
if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP))) && erP)
|
||||
{
|
||||
// register the event listeners with the DOM event reveiver
|
||||
//register focus and key listeners
|
||||
nsCOMPtr<nsIDOMEventReceiver> erP = do_QueryInterface(mContent);
|
||||
if (erP) {
|
||||
// register the event listeners with the DOM event receiver
|
||||
rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
|
||||
// XXXbryner do we need to check for a null presshell here?
|
||||
|
@ -3017,6 +3183,22 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
||||
erP->GetSystemEventGroup(getter_AddRefs(systemGroup));
|
||||
nsCOMPtr<nsIDOM3EventTarget> dom3Targ = do_QueryInterface(mContent);
|
||||
if (dom3Targ) {
|
||||
// cast because of ambiguous base
|
||||
nsIDOMEventListener *listener = NS_STATIC_CAST(nsIDOMKeyListener*,
|
||||
mTextListener);
|
||||
|
||||
dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keydown"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
dom3Targ->AddGroupedEventListener(NS_LITERAL_STRING("keyup"),
|
||||
listener, PR_FALSE, systemGroup);
|
||||
}
|
||||
|
||||
while(first)
|
||||
{
|
||||
nsIView *view = first->GetView();
|
||||
|
@ -3105,3 +3287,10 @@ nsTextControlFrame::HandleEvent(nsPresContext* aPresContext,
|
|||
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsTextControlFrame::ShutDown()
|
||||
{
|
||||
NS_IF_RELEASE(sNativeTextAreaBindings);
|
||||
NS_IF_RELEASE(sNativeInputBindings);
|
||||
}
|
||||
|
|
|
@ -212,6 +212,9 @@ public: //for methods who access nsTextControlFrame directly
|
|||
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
|
||||
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
|
||||
|
||||
/* called to free up native keybinding services */
|
||||
static NS_HIDDEN_(void) ShutDown();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,6 +71,7 @@ EXPORTS = \
|
|||
nsIDragSessionOS2.h \
|
||||
nsIXRemoteWidgetHelper.h \
|
||||
nsIPluginWidget.h \
|
||||
nsINativeKeyBindings.h \
|
||||
$(NULL)
|
||||
|
||||
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* IBM Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef nsINativeKeyBindings_h_
|
||||
#define nsINativeKeyBindings_h_
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
#define NS_INATIVEKEYBINDINGS_IID \
|
||||
{0x606c54e7, 0x0593, 0x4750, {0x99, 0xd9, 0x4e, 0x1b, 0xcc, 0xec, 0x98, 0xd9}}
|
||||
|
||||
#define NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX \
|
||||
"@mozilla.org/widget/native-key-bindings;1?type="
|
||||
|
||||
struct nsNativeKeyEvent
|
||||
{
|
||||
PRUint32 keyCode;
|
||||
PRUint32 charCode;
|
||||
PRBool altKey;
|
||||
PRBool ctrlKey;
|
||||
PRBool shiftKey;
|
||||
PRBool metaKey;
|
||||
};
|
||||
|
||||
class nsINativeKeyBindings : public nsISupports
|
||||
{
|
||||
public:
|
||||
typedef void (*DoCommandCallback)(const char *, void*);
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_INATIVEKEYBINDINGS_IID)
|
||||
|
||||
virtual NS_HIDDEN_(PRBool) KeyDown(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void *aCallbackData) = 0;
|
||||
|
||||
virtual NS_HIDDEN_(PRBool) KeyPress(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void *aCallbackData) = 0;
|
||||
|
||||
virtual NS_HIDDEN_(PRBool) KeyUp(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void *aCallbackData) = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -81,6 +81,7 @@ CPPSRCS = \
|
|||
nsDragService.cpp \
|
||||
nsFilePicker.cpp \
|
||||
nsSound.cpp \
|
||||
nsNativeKeyBindings.cpp \
|
||||
$(NULL)
|
||||
|
||||
# build our subdirs, too
|
||||
|
|
|
@ -215,6 +215,53 @@ GdkKeyCodeToDOMKeyCode(int aKeysym)
|
|||
return((int)0);
|
||||
}
|
||||
|
||||
int
|
||||
DOMKeyCodeToGdkKeyCode(PRUint32 aKeysym)
|
||||
{
|
||||
int i, length = 0;
|
||||
|
||||
// First, try to handle alphanumeric input, not listed in nsKeycodes:
|
||||
// most likely, more letters will be getting typed in than things in
|
||||
// the key list, so we will look through these first.
|
||||
|
||||
if (aKeysym >= NS_VK_A && aKeysym <= NS_VK_Z)
|
||||
// gdk and DOM both use the ASCII codes for these keys.
|
||||
return aKeysym;
|
||||
|
||||
// numbers
|
||||
if (aKeysym >= NS_VK_0 && aKeysym <= NS_VK_9)
|
||||
// gdk and DOM both use the ASCII codes for these keys.
|
||||
return aKeysym - GDK_0 + NS_VK_0;
|
||||
|
||||
// keypad numbers
|
||||
if (aKeysym >= NS_VK_NUMPAD0 && aKeysym <= NS_VK_NUMPAD9)
|
||||
return aKeysym - NS_VK_NUMPAD0 + GDK_KP_0;
|
||||
|
||||
// map Sun Keyboard special keysyms
|
||||
if (IS_XSUN_XSERVER(GDK_DISPLAY())) {
|
||||
length = NS_ARRAY_LENGTH(nsSunKeycodes);
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (nsSunKeycodes[i].vkCode == aKeysym) {
|
||||
return nsSunKeycodes[i].keysym;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// misc other things
|
||||
length = NS_ARRAY_LENGTH(nsKeycodes);
|
||||
for (i = 0; i < length; ++i) {
|
||||
if (nsKeycodes[i].vkCode == aKeysym) {
|
||||
return nsKeycodes[i].keysym;
|
||||
}
|
||||
}
|
||||
|
||||
// function keys
|
||||
if (aKeysym >= NS_VK_F1 && aKeysym <= NS_VK_F9)
|
||||
return aKeysym - NS_VK_F1 + GDK_F1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert gdk key event keyvals to char codes if printable, 0 otherwise
|
||||
PRUint32 nsConvertCharCodeToUnicode(GdkEventKey* aEvent)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#define __nsGdkKeyUtils_h__
|
||||
|
||||
int GdkKeyCodeToDOMKeyCode (int aKeysym);
|
||||
int DOMKeyCodeToGdkKeyCode (PRUint32 aKeysym);
|
||||
PRUint32 nsConvertCharCodeToUnicode (GdkEventKey* aEvent);
|
||||
|
||||
#endif /* __nsGdkKeyUtils_h__ */
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* IBM Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsNativeKeyBindings.h"
|
||||
#include "nsString.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsGtkKeyUtils.h"
|
||||
|
||||
#include <gtk/gtkentry.h>
|
||||
#include <gtk/gtktextview.h>
|
||||
#include <gtk/gtkbindings.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
static nsINativeKeyBindings::DoCommandCallback gCurrentCallback;
|
||||
static void *gCurrentCallbackData;
|
||||
|
||||
// Common GtkEntry and GtkTextView signals
|
||||
static void
|
||||
copy_clipboard_cb(GtkWidget *w, gpointer user_data)
|
||||
{
|
||||
gCurrentCallback("cmd_copy", gCurrentCallbackData);
|
||||
g_signal_stop_emission_by_name(w, "copy_clipboard");
|
||||
}
|
||||
|
||||
static void
|
||||
cut_clipboard_cb(GtkWidget *w, gpointer user_data)
|
||||
{
|
||||
gCurrentCallback("cmd_cut", gCurrentCallbackData);
|
||||
g_signal_stop_emission_by_name(w, "cut_clipboard");
|
||||
}
|
||||
|
||||
// GTK distinguishes between display lines (wrapped, as they appear on the
|
||||
// screen) and paragraphs, which are runs of text terminated by a newline.
|
||||
// We don't have this distinction, so we always use editor's notion of
|
||||
// lines, which are newline-terminated.
|
||||
|
||||
static const char *const sDeleteCommands[][2] = {
|
||||
// backward, forward
|
||||
{ "cmd_deleteCharBackward", "cmd_deleteCharForward" }, // CHARS
|
||||
{ "cmd_deleteWordBackward", "cmd_deleteWordForward" }, // WORD_ENDS
|
||||
{ "cmd_deleteWordBackward", "cmd_deleteWordForward" }, // WORDS
|
||||
{ "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // LINES
|
||||
{ "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // LINE_ENDS
|
||||
{ "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // PARAGRAPH_ENDS
|
||||
{ "cmd_deleteToBeginningOfLine", "cmd_deleteToEndOfLine" }, // PARAGRAPHS
|
||||
// This deletes from the end of the previous word to the beginning of the
|
||||
// next word, but only if the caret is not in a word.
|
||||
// XXX need to implement in editor
|
||||
{ nsnull, nsnull } // WHITESPACE
|
||||
};
|
||||
|
||||
static void
|
||||
delete_from_cursor_cb(GtkWidget *w, GtkDeleteType del_type,
|
||||
gint count, gpointer user_data)
|
||||
{
|
||||
g_signal_stop_emission_by_name(w, "delete_from_cursor");
|
||||
|
||||
PRBool forward = count > 0;
|
||||
if (PRUint32(del_type) >= NS_ARRAY_LENGTH(sDeleteCommands)) {
|
||||
// unsupported deletion type
|
||||
return;
|
||||
}
|
||||
|
||||
if (del_type == GTK_DELETE_WORDS) {
|
||||
// This works like word_ends, except we first move the caret to the
|
||||
// beginning/end of the current word.
|
||||
if (forward) {
|
||||
gCurrentCallback("cmd_wordNext", gCurrentCallbackData);
|
||||
gCurrentCallback("cmd_wordPrevious", gCurrentCallbackData);
|
||||
} else {
|
||||
gCurrentCallback("cmd_wordPrevious", gCurrentCallbackData);
|
||||
gCurrentCallback("cmd_wordNext", gCurrentCallbackData);
|
||||
}
|
||||
} else if (del_type == GTK_DELETE_DISPLAY_LINES ||
|
||||
del_type == GTK_DELETE_PARAGRAPHS) {
|
||||
|
||||
// This works like display_line_ends, except we first move the caret to the
|
||||
// beginning/end of the current line.
|
||||
if (forward) {
|
||||
gCurrentCallback("cmd_beginLine", gCurrentCallbackData);
|
||||
} else {
|
||||
gCurrentCallback("cmd_endLine", gCurrentCallbackData);
|
||||
}
|
||||
}
|
||||
|
||||
const char *cmd = sDeleteCommands[del_type][forward];
|
||||
if (!cmd)
|
||||
return; // unsupported command
|
||||
|
||||
count = PR_ABS(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
gCurrentCallback(cmd, gCurrentCallbackData);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const sMoveCommands[][2][2] = {
|
||||
// non-extend { backward, forward }, extend { backward, forward }
|
||||
// GTK differentiates between logical position, which is prev/next,
|
||||
// and visual position, which is always left/right.
|
||||
// We should fix this to work the same way for RTL text input.
|
||||
{ // LOGICAL_POSITIONS
|
||||
{ "cmd_charPrevious", "cmd_charNext" },
|
||||
{ "cmd_selectCharPrevious", "cmd_selectCharNext" }
|
||||
},
|
||||
{ // VISUAL_POSITIONS
|
||||
{ "cmd_charPrevious", "cmd_charNext" },
|
||||
{ "cmd_selectCharPrevious", "cmd_selectCharNext" }
|
||||
},
|
||||
{ // WORDS
|
||||
{ "cmd_wordPrevious", "cmd_wordNext" },
|
||||
{ "cmd_selectWordPrevious", "cmd_selectWordNext" }
|
||||
},
|
||||
{ // DISPLAY_LINES
|
||||
{ "cmd_linePrevious", "cmd_lineNext" },
|
||||
{ "cmd_selectLinePrevious", "cmd_selectLineNext" }
|
||||
},
|
||||
{ // DISPLAY_LINE_ENDS
|
||||
{ "cmd_beginLine", "cmd_endLine" },
|
||||
{ "cmd_selectBeginLine", "cmd_selectEndLine" }
|
||||
},
|
||||
{ // PARAGRAPHS
|
||||
{ "cmd_linePrevious", "cmd_lineNext" },
|
||||
{ "cmd_selectLinePrevious", "cmd_selectLineNext" }
|
||||
},
|
||||
{ // PARAGRAPH_ENDS
|
||||
{ "cmd_beginLine", "cmd_endLine" },
|
||||
{ "cmd_selectBeginLine", "cmd_selectEndLine" }
|
||||
},
|
||||
{ // PAGES
|
||||
{ "cmd_movePageUp", "cmd_movePageDown" },
|
||||
{ "cmd_selectPageUp", "cmd_selectPageDown" }
|
||||
},
|
||||
{ // BUFFER_ENDS
|
||||
{ "cmd_moveTop", "cmd_moveBottom" },
|
||||
{ "cmd_selectTop", "cmd_selectBottom" }
|
||||
},
|
||||
{ // HORIZONTAL_PAGES (unsupported)
|
||||
{ nsnull, nsnull },
|
||||
{ nsnull, nsnull }
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
move_cursor_cb(GtkWidget *w, GtkMovementStep step, gint count,
|
||||
gboolean extend_selection, gpointer user_data)
|
||||
{
|
||||
g_signal_stop_emission_by_name(w, "move_cursor");
|
||||
PRBool forward = count > 0;
|
||||
if (PRUint32(step) >= NS_ARRAY_LENGTH(sMoveCommands)) {
|
||||
// unsupported movement type
|
||||
return;
|
||||
}
|
||||
|
||||
const char *cmd = sMoveCommands[step][extend_selection][forward];
|
||||
if (!cmd)
|
||||
return; // unsupported command
|
||||
|
||||
|
||||
count = PR_ABS(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
gCurrentCallback(cmd, gCurrentCallbackData);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
paste_clipboard_cb(GtkWidget *w, gpointer user_data)
|
||||
{
|
||||
gCurrentCallback("cmd_paste", gCurrentCallbackData);
|
||||
g_signal_stop_emission_by_name(w, "paste_clipboard");
|
||||
}
|
||||
|
||||
// GtkTextView-only signals
|
||||
static void
|
||||
select_all_cb(GtkWidget *w, gboolean select, gpointer user_data)
|
||||
{
|
||||
gCurrentCallback("cmd_selectAll", gCurrentCallbackData);
|
||||
g_signal_stop_emission_by_name(w, "select_all");
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeKeyBindings::Init(NativeKeyBindingsType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case eKeyBindings_Input:
|
||||
mNativeTarget = gtk_entry_new();
|
||||
break;
|
||||
case eKeyBindings_TextArea:
|
||||
mNativeTarget = gtk_text_view_new();
|
||||
g_signal_connect(G_OBJECT(mNativeTarget), "select_all",
|
||||
G_CALLBACK(select_all_cb), this);
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_connect(G_OBJECT(mNativeTarget), "copy_clipboard",
|
||||
G_CALLBACK(copy_clipboard_cb), this);
|
||||
g_signal_connect(G_OBJECT(mNativeTarget), "cut_clipboard",
|
||||
G_CALLBACK(cut_clipboard_cb), this);
|
||||
g_signal_connect(G_OBJECT(mNativeTarget), "delete_from_cursor",
|
||||
G_CALLBACK(delete_from_cursor_cb), this);
|
||||
g_signal_connect(G_OBJECT(mNativeTarget), "move_cursor",
|
||||
G_CALLBACK(move_cursor_cb), this);
|
||||
g_signal_connect(G_OBJECT(mNativeTarget), "paste_clipboard",
|
||||
G_CALLBACK(paste_clipboard_cb), this);
|
||||
}
|
||||
|
||||
nsNativeKeyBindings::~nsNativeKeyBindings()
|
||||
{
|
||||
gtk_widget_destroy(mNativeTarget);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsNativeKeyBindings, nsINativeKeyBindings)
|
||||
|
||||
PRBool
|
||||
nsNativeKeyBindings::KeyDown(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback, void *aCallbackData)
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsNativeKeyBindings::KeyPress(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback, void *aCallbackData)
|
||||
{
|
||||
PRUint32 keyCode;
|
||||
|
||||
if (aEvent.charCode != 0)
|
||||
keyCode = gdk_unicode_to_keyval(aEvent.charCode);
|
||||
else
|
||||
keyCode = DOMKeyCodeToGdkKeyCode(aEvent.keyCode);
|
||||
|
||||
int modifiers = 0;
|
||||
if (aEvent.altKey)
|
||||
modifiers |= GDK_MOD1_MASK;
|
||||
if (aEvent.ctrlKey)
|
||||
modifiers |= GDK_CONTROL_MASK;
|
||||
if (aEvent.shiftKey)
|
||||
modifiers |= GDK_SHIFT_MASK;
|
||||
// we don't support meta
|
||||
|
||||
gCurrentCallback = aCallback;
|
||||
gCurrentCallbackData = aCallbackData;
|
||||
|
||||
PRBool handled = PR_FALSE;
|
||||
|
||||
if (gtk_bindings_activate(GTK_OBJECT(mNativeTarget),
|
||||
keyCode, GdkModifierType(modifiers))) {
|
||||
handled = PR_TRUE;
|
||||
}
|
||||
|
||||
gCurrentCallback = nsnull;
|
||||
gCurrentCallbackData = nsnull;
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsNativeKeyBindings::KeyUp(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback, void *aCallbackData)
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* IBM Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef nsNativeKeyBindings_h_
|
||||
#define nsNativeKeyBindings_h_
|
||||
|
||||
// X.h defines KeyPress
|
||||
#ifdef KeyPress
|
||||
#undef KeyPress
|
||||
#endif
|
||||
|
||||
#include "nsINativeKeyBindings.h"
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
enum NativeKeyBindingsType {
|
||||
eKeyBindings_Input,
|
||||
eKeyBindings_TextArea
|
||||
};
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSINPUT_CID \
|
||||
{0x5c337258, 0xa580, 0x472e, {0x86, 0x15, 0xf2, 0x77, 0xdd, 0xc5, 0xbb, 0x06}}
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSINPUT_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "input"
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSTEXTAREA_CID \
|
||||
{0x2a898043, 0x180f, 0x4c8b, {0x8e, 0x54, 0x41, 0x0c, 0x7a, 0x54, 0x0f, 0x27}}
|
||||
|
||||
#define NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID \
|
||||
NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "textarea"
|
||||
|
||||
class nsNativeKeyBindings : public nsINativeKeyBindings
|
||||
{
|
||||
public:
|
||||
NS_HIDDEN_(void) Init(NativeKeyBindingsType aType);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsINativeKeyBindings
|
||||
virtual NS_HIDDEN_(PRBool) KeyDown(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void *aCallbackData);
|
||||
|
||||
virtual NS_HIDDEN_(PRBool) KeyPress(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void *aCallbackData);
|
||||
|
||||
virtual NS_HIDDEN_(PRBool) KeyUp(const nsNativeKeyEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void *aCallbackData);
|
||||
|
||||
private:
|
||||
~nsNativeKeyBindings() NS_HIDDEN;
|
||||
|
||||
GtkWidget *mNativeTarget;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -51,6 +51,7 @@
|
|||
#include "nsFilePicker.h"
|
||||
#include "nsSound.h"
|
||||
#include "nsBidiKeyboard.h"
|
||||
#include "nsNativeKeyBindings.h"
|
||||
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
@ -147,6 +148,49 @@ nsFilePickerUnregisterSelf(nsIComponentManager *aCompMgr,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static NS_IMETHODIMP
|
||||
nsNativeKeyBindingsConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult,
|
||||
NativeKeyBindingsType aKeyBindingsType)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsNativeKeyBindings *inst;
|
||||
|
||||
*aResult = NULL;
|
||||
if (NULL != aOuter) {
|
||||
rv = NS_ERROR_NO_AGGREGATION;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_NEWXPCOM(inst, nsNativeKeyBindings);
|
||||
if (NULL == inst) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
return rv;
|
||||
}
|
||||
NS_ADDREF(inst);
|
||||
inst->Init(aKeyBindingsType);
|
||||
rv = inst->QueryInterface(aIID, aResult);
|
||||
NS_RELEASE(inst);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static NS_IMETHODIMP
|
||||
nsNativeKeyBindingsInputConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult)
|
||||
{
|
||||
return nsNativeKeyBindingsConstructor(aOuter, aIID, aResult,
|
||||
eKeyBindings_Input);
|
||||
}
|
||||
|
||||
static NS_IMETHODIMP
|
||||
nsNativeKeyBindingsTextAreaConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult)
|
||||
{
|
||||
return nsNativeKeyBindingsConstructor(aOuter, aIID, aResult,
|
||||
eKeyBindings_TextArea);
|
||||
}
|
||||
|
||||
static const nsModuleComponentInfo components[] =
|
||||
{
|
||||
|
@ -204,6 +248,14 @@ static const nsModuleComponentInfo components[] =
|
|||
NS_BIDIKEYBOARD_CID,
|
||||
"@mozilla.org/widget/bidikeyboard;1",
|
||||
nsBidiKeyboardConstructor },
|
||||
{ "Input Native Keybindings",
|
||||
NS_NATIVEKEYBINDINGSINPUT_CID,
|
||||
NS_NATIVEKEYBINDINGSINPUT_CONTRACTID,
|
||||
nsNativeKeyBindingsInputConstructor },
|
||||
{ "TextArea Native Keybindings",
|
||||
NS_NATIVEKEYBINDINGSTEXTAREA_CID,
|
||||
NS_NATIVEKEYBINDINGSTEXTAREA_CONTRACTID,
|
||||
nsNativeKeyBindingsTextAreaConstructor }
|
||||
};
|
||||
|
||||
PR_STATIC_CALLBACK(void)
|
||||
|
|
Загрузка…
Ссылка в новой задаче