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:
bryner%brianryner.com 2004-09-07 21:21:48 +00:00
Родитель b89a09b444
Коммит d342e8f7b4
18 изменённых файлов: 1089 добавлений и 16 удалений

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

@ -299,6 +299,7 @@ content/xbl/Makefile
content/xbl/public/Makefile content/xbl/public/Makefile
content/xbl/src/Makefile content/xbl/src/Makefile
content/xbl/builtin/Makefile content/xbl/builtin/Makefile
content/xbl/builtin/gtk2/Makefile
content/xbl/builtin/unix/Makefile content/xbl/builtin/unix/Makefile
content/xbl/builtin/win/Makefile content/xbl/builtin/win/Makefile
content/xsl/Makefile content/xsl/Makefile

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

@ -48,9 +48,13 @@ else
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
DIRS = mac DIRS = mac
else else
ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
DIRS = gtk2
else
DIRS = unix DIRS = unix
endif endif
endif endif
endif
include $(topsrcdir)/config/rules.mk 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 "nsStyleSet.h"
#include "nsImageFrame.h" #include "nsImageFrame.h"
#include "nsILanguageAtomService.h" #include "nsILanguageAtomService.h"
#include "nsTextControlFrame.h"
// view stuff // view stuff
#include "nsViewsCID.h" #include "nsViewsCID.h"
@ -417,6 +418,7 @@ Shutdown()
GlobalWindowImpl::ShutDown(); GlobalWindowImpl::ShutDown();
nsDOMClassInfo::ShutDown(); nsDOMClassInfo::ShutDown();
nsTextControlFrame::ShutDown();
} }
#ifdef NS_DEBUG #ifdef NS_DEBUG

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

@ -120,6 +120,10 @@
#include "nsIDOMText.h" //for multiline getselection #include "nsIDOMText.h" //for multiline getselection
#include "nsNodeInfoManager.h" #include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h" #include "nsContentCreatorFunctions.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMEventGroup.h"
#include "nsIDOM3EventTarget.h"
#include "nsINativeKeyBindings.h"
#ifdef IBMBIDI #ifdef IBMBIDI
#include "nsIBidiKeyboard.h" #include "nsIBidiKeyboard.h"
@ -138,8 +142,12 @@ static const PRInt32 DEFAULT_COLS = 20;
static const PRInt32 DEFAULT_ROWS = 1; static const PRInt32 DEFAULT_ROWS = 1;
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2; static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
static nsINativeKeyBindings *sNativeInputBindings = nsnull;
static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
class nsTextInputListener : public nsISelectionListener, class nsTextInputListener : public nsISelectionListener,
public nsIDOMFocusListener, public nsIDOMFocusListener,
public nsIDOMKeyListener,
public nsIEditorObserver, public nsIEditorObserver,
public nsSupportsWeakReference public nsSupportsWeakReference
{ {
@ -169,12 +177,19 @@ public:
NS_IMETHOD Blur (nsIDOMEvent* aEvent); NS_IMETHOD Blur (nsIDOMEvent* aEvent);
/* END interfaces from nsIDOMFocusListener*/ /* END interfaces from nsIDOMFocusListener*/
// nsIDOMKeyListener
NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
NS_DECL_NSIEDITOROBSERVER NS_DECL_NSIEDITOROBSERVER
protected: protected:
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate); nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
protected: protected:
nsTextControlFrame* mFrame; // weak reference nsTextControlFrame* mFrame; // weak reference
@ -211,9 +226,18 @@ nsTextInputListener::~nsTextInputListener()
{ {
} }
NS_IMPL_ISUPPORTS5(nsTextInputListener, nsISelectionListener, NS_IMPL_ADDREF(nsTextInputListener)
nsIDOMEventListener, nsIDOMFocusListener, NS_IMPL_RELEASE(nsTextInputListener)
nsIEditorObserver, nsISupportsWeakReference)
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 // BEGIN nsIDOMSelectionListener
@ -313,6 +337,103 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent)
// END nsIFocusListener // 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 // BEGIN nsIEditorObserver
@ -371,6 +492,36 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
return domWindow->UpdateCommands(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 // END nsTextInputListener
@ -1255,6 +1406,22 @@ nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
{ {
erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener)); 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; mDidPreDestroy = PR_TRUE;
@ -3005,11 +3172,10 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE); scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
} }
//register keylistener //register focus and key listeners
nsCOMPtr<nsIDOMEventReceiver> erP; nsCOMPtr<nsIDOMEventReceiver> erP = do_QueryInterface(mContent);
if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP))) && erP) if (erP) {
{ // register the event listeners with the DOM event receiver
// register the event listeners with the DOM event reveiver
rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener)); rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener"); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
// XXXbryner do we need to check for a null presshell here? // XXXbryner do we need to check for a null presshell here?
@ -3017,6 +3183,22 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
return NS_ERROR_FAILURE; 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) while(first)
{ {
nsIView *view = first->GetView(); nsIView *view = first->GetView();
@ -3105,3 +3287,10 @@ nsTextControlFrame::HandleEvent(nsPresContext* aPresContext,
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus); 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 DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition); nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
/* called to free up native keybinding services */
static NS_HIDDEN_(void) ShutDown();
protected: protected:
/** /**

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

@ -120,6 +120,10 @@
#include "nsIDOMText.h" //for multiline getselection #include "nsIDOMText.h" //for multiline getselection
#include "nsNodeInfoManager.h" #include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h" #include "nsContentCreatorFunctions.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMEventGroup.h"
#include "nsIDOM3EventTarget.h"
#include "nsINativeKeyBindings.h"
#ifdef IBMBIDI #ifdef IBMBIDI
#include "nsIBidiKeyboard.h" #include "nsIBidiKeyboard.h"
@ -138,8 +142,12 @@ static const PRInt32 DEFAULT_COLS = 20;
static const PRInt32 DEFAULT_ROWS = 1; static const PRInt32 DEFAULT_ROWS = 1;
static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2; static const PRInt32 DEFAULT_ROWS_TEXTAREA = 2;
static nsINativeKeyBindings *sNativeInputBindings = nsnull;
static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
class nsTextInputListener : public nsISelectionListener, class nsTextInputListener : public nsISelectionListener,
public nsIDOMFocusListener, public nsIDOMFocusListener,
public nsIDOMKeyListener,
public nsIEditorObserver, public nsIEditorObserver,
public nsSupportsWeakReference public nsSupportsWeakReference
{ {
@ -169,12 +177,19 @@ public:
NS_IMETHOD Blur (nsIDOMEvent* aEvent); NS_IMETHOD Blur (nsIDOMEvent* aEvent);
/* END interfaces from nsIDOMFocusListener*/ /* END interfaces from nsIDOMFocusListener*/
// nsIDOMKeyListener
NS_IMETHOD KeyDown(nsIDOMEvent *aKeyEvent);
NS_IMETHOD KeyPress(nsIDOMEvent *aKeyEvent);
NS_IMETHOD KeyUp(nsIDOMEvent *aKeyEvent);
NS_DECL_NSIEDITOROBSERVER NS_DECL_NSIEDITOROBSERVER
protected: protected:
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate); nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
NS_HIDDEN_(nsINativeKeyBindings*) GetKeyBindings();
protected: protected:
nsTextControlFrame* mFrame; // weak reference nsTextControlFrame* mFrame; // weak reference
@ -211,9 +226,18 @@ nsTextInputListener::~nsTextInputListener()
{ {
} }
NS_IMPL_ISUPPORTS5(nsTextInputListener, nsISelectionListener, NS_IMPL_ADDREF(nsTextInputListener)
nsIDOMEventListener, nsIDOMFocusListener, NS_IMPL_RELEASE(nsTextInputListener)
nsIEditorObserver, nsISupportsWeakReference)
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 // BEGIN nsIDOMSelectionListener
@ -313,6 +337,103 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent)
// END nsIFocusListener // 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 // BEGIN nsIEditorObserver
@ -371,6 +492,36 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
return domWindow->UpdateCommands(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 // END nsTextInputListener
@ -1255,6 +1406,22 @@ nsTextControlFrame::PreDestroy(nsPresContext* aPresContext)
{ {
erP->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener)); 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; mDidPreDestroy = PR_TRUE;
@ -3005,11 +3172,10 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE); scrollableFrame->SetScrollbarVisibility(PR_FALSE, PR_FALSE);
} }
//register keylistener //register focus and key listeners
nsCOMPtr<nsIDOMEventReceiver> erP; nsCOMPtr<nsIDOMEventReceiver> erP = do_QueryInterface(mContent);
if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP))) && erP) if (erP) {
{ // register the event listeners with the DOM event receiver
// register the event listeners with the DOM event reveiver
rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener)); rv = erP->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMFocusListener *,mTextListener), NS_GET_IID(nsIDOMFocusListener));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener"); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener");
// XXXbryner do we need to check for a null presshell here? // XXXbryner do we need to check for a null presshell here?
@ -3017,6 +3183,22 @@ nsTextControlFrame::SetInitialChildList(nsPresContext* aPresContext,
return NS_ERROR_FAILURE; 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) while(first)
{ {
nsIView *view = first->GetView(); nsIView *view = first->GetView();
@ -3105,3 +3287,10 @@ nsTextControlFrame::HandleEvent(nsPresContext* aPresContext,
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus); 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 DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition); nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
/* called to free up native keybinding services */
static NS_HIDDEN_(void) ShutDown();
protected: protected:
/** /**

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

@ -71,6 +71,7 @@ EXPORTS = \
nsIDragSessionOS2.h \ nsIDragSessionOS2.h \
nsIXRemoteWidgetHelper.h \ nsIXRemoteWidgetHelper.h \
nsIPluginWidget.h \ nsIPluginWidget.h \
nsINativeKeyBindings.h \
$(NULL) $(NULL)
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) 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 \ nsDragService.cpp \
nsFilePicker.cpp \ nsFilePicker.cpp \
nsSound.cpp \ nsSound.cpp \
nsNativeKeyBindings.cpp \
$(NULL) $(NULL)
# build our subdirs, too # build our subdirs, too

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

@ -215,6 +215,53 @@ GdkKeyCodeToDOMKeyCode(int aKeysym)
return((int)0); 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 // Convert gdk key event keyvals to char codes if printable, 0 otherwise
PRUint32 nsConvertCharCodeToUnicode(GdkEventKey* aEvent) PRUint32 nsConvertCharCodeToUnicode(GdkEventKey* aEvent)
{ {

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

@ -40,6 +40,7 @@
#define __nsGdkKeyUtils_h__ #define __nsGdkKeyUtils_h__
int GdkKeyCodeToDOMKeyCode (int aKeysym); int GdkKeyCodeToDOMKeyCode (int aKeysym);
int DOMKeyCodeToGdkKeyCode (PRUint32 aKeysym);
PRUint32 nsConvertCharCodeToUnicode (GdkEventKey* aEvent); PRUint32 nsConvertCharCodeToUnicode (GdkEventKey* aEvent);
#endif /* __nsGdkKeyUtils_h__ */ #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 "nsFilePicker.h"
#include "nsSound.h" #include "nsSound.h"
#include "nsBidiKeyboard.h" #include "nsBidiKeyboard.h"
#include "nsNativeKeyBindings.h"
#include "nsIComponentRegistrar.h" #include "nsIComponentRegistrar.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
@ -147,6 +148,49 @@ nsFilePickerUnregisterSelf(nsIComponentManager *aCompMgr,
return rv; 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[] = static const nsModuleComponentInfo components[] =
{ {
@ -204,6 +248,14 @@ static const nsModuleComponentInfo components[] =
NS_BIDIKEYBOARD_CID, NS_BIDIKEYBOARD_CID,
"@mozilla.org/widget/bidikeyboard;1", "@mozilla.org/widget/bidikeyboard;1",
nsBidiKeyboardConstructor }, 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) PR_STATIC_CALLBACK(void)