在minimo中用方向键切换焦点

minimo中用方向键切换焦点

转载时请注明出处和作者联系方式

作者联系方式:李先静 <xianjimli at hotmail dot com>

XUL编写的minimo实在太慢了,起动过程足足要40秒钟,我对它已经完全失去信心了。前几天发现用GTK+编写的minimo则要快得多,第二次起动仅仅花了7秒钟时间,这要让我精神大振,可惜mozilla中所带的GTK+编写的minimo已经没有人维护了,代码很凌乱,很多功能也都不支持。

最后我们决定用GTK+重新编写minimo,而界面完全模仿Windows Mobile5.0 中的IE。经过一周时间的努力,基本功能已经完成,只是还有少数功能需要完善。其中方向键切换焦点就是其中的问题之一,在firefox里,默认情况是不能用方向键在网页中切换焦点的,切换焦点只能用tab键,而普通手机根本没有tab键,我们希望能用方向键代替tab实现焦点切换。

以前在阅读mozilla代码时,我记得有个扩展可以实现这个功能,不过忘了具体是哪个扩展了,今天在extension目录里找了一下,很快确认是spatialnavigation扩展,spatial取得真不怎么样,我还以为是什么3D相关的东西的呢,还好navigation给了一些提示。

Spatialnavigation的实现原理很简单:

NS_IMETHODIMP
nsSpatialNavigation::Init(nsIDOMWindow *aWindow)
{
mTopWindow = aWindow;

nsCOMPtr<nsIDOM3EventTarget> target;
nsCOMPtr<nsIDOMEventGroup> systemGroup;
nsresult rv = getEventTargetFromWindow(aWindow, getter_AddRefs(target), getter_AddRefs(systemGroup));
if(NS_FAILED(rv))
returnrv;

target->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
static_cast<nsIDOMKeyListener*>(this),
PR_FALSE,
systemGroup);

returnNS_OK;
}

这个函数向DOMWindow注册按键事件,当有按键发生时,nsSpatialNavigation相关虚函数就会被调用。

NS_IMETHODIMP
nsSpatialNavigation::KeyDown(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
PRBool enabled;
prefBranch->GetBoolPref("snav.enabled", &enabled);
if(!enabled) //this doesn't work.wtf? if (!mService->mEnabled)
returnNS_OK;


nsCOMPtr<nsIDOMNSUIEvent> uiEvent(do_QueryInterface(aEvent));
if(uiEvent)
{
// If a web page wants to use the keys mapped to our
// move, they have to use evt.preventDefault() after
// they get the key

PRBool preventDefault;
uiEvent->GetPreventDefault(&preventDefault);
if(preventDefault)
returnNS_OK;
}

PRInt32 formControlType = -1;
// check to see if we are in a text field.
// based on nsTypeAheadFind.

//nsEvent should be renamed.
nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aEvent);
if(!nsEvent)
returnNS_ERROR_FAILURE;

nsCOMPtr<nsIDOMEventTarget> domEventTarget;
nsEvent->GetOriginalTarget(getter_AddRefs(domEventTarget));

nsCOMPtr<nsIContent> targetContent = do_QueryInterface(domEventTarget);

if(targetContent->IsNodeOfType(nsINode::eXUL))
returnNS_OK;

if(targetContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL))
{
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(targetContent));
formControlType = formControl->GetType();

if(mService->mIgnoreTextFields)
{
if(formControlType == NS_FORM_TEXTAREA ||
formControlType == NS_FORM_INPUT_TEXT ||
formControlType == NS_FORM_INPUT_PASSWORD ||
formControlType == NS_FORM_INPUT_FILE)
{
returnNS_OK;
}
}
}
elseif(mService->mIgnoreTextFields && targetContent->IsNodeOfType(nsINode::eHTML))
{
// Test for isindex, a deprecated kind of text field. We're using a string
// compare because <isindex> is not considered a form control, so it does
// not support nsIFormControl or eHTML_FORM_CONTROL, and it's not worth
// having a table of atoms just for it.

if(isContentOfType(targetContent, "isindex"))
returnNS_OK;
}

if(formControlType == NS_FORM_INPUT_TEXT ||
formControlType == NS_FORM_INPUT_PASSWORD)
{
PRInt32 selectionStart, textLength;
nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(targetContent);
if(input) {
input->GetSelectionStart (&selectionStart);
input->GetTextLength (&textLength);
} else{
nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea = do_QueryInterface(targetContent);
if(textArea) {
textArea->GetSelectionStart (&selectionStart);
textArea->GetTextLength (&textLength);
}
}

if(textLength != 0&& selectionStart != 0)
returnNS_OK;
}

// We're using this key, no one else should
aEvent->StopPropagation();
aEvent->PreventDefault();

returnLeft();
}

if(keyCode == mService->mKeyCodeRight)
{
// ************************************************************************************
// NS_FORM_TEXTAREA cases:

// ************************************************************************************
// NS_FORM_INPUT_TEXT | NS_FORM_INPUT_PASSWORD | NS_FORM_INPUT_FILE cases

if(formControlType == NS_FORM_INPUT_TEXT ||
formControlType == NS_FORM_INPUT_PASSWORD)
{
PRInt32 selectionEnd, textLength;
nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(targetContent);
if(input) {
input->GetSelectionEnd (&selectionEnd);
input->GetTextLength (&textLength);
} else{
nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea = do_QueryInterface(targetContent);
if(textArea) {
textArea->GetSelectionEnd (&selectionEnd);
textArea->GetTextLength (&textLength);
}
}

// going down.

if(textLength!= selectionEnd)
returnNS_OK;
}

aEvent->StopPropagation();
aEvent->PreventDefault();
returnRight();
}

if(keyCode == mService->mKeyCodeUp)
{

// If we are going up or down, in a select, lets not
// navigate.
//
// FIX: What we really want to do is determine if we are
// at the start or the end fo the form element, and
// based on the selected position we decide to nav. or
// not.

// ************************************************************************************
// NS_FORM_SELECT cases:
// * if it is a select form of 'size' attr != than '1' then we do as above.

// * if it is a select form of 'size' attr == than '1', snav can take care of it.
// if (formControlType == NS_FORM_SELECT)
// return NS_OK;

aEvent->StopPropagation();
aEvent->PreventDefault();
returnUp();
}

if(keyCode == mService->mKeyCodeDown)
{
// If we are going up or down, in a select, lets not
// navigate.
//
// FIX: What we really want to do is determine if we are
// at the start or the end fo the form element, and
// based on the selected position we decide to nav. or
// not.

// ************************************************************************************
// NS_FORM_SELECT cases:
// * if it is a select form of 'size' attr != than '1' then we do as above.

// * if it is a select form of 'size' attr == than '1', snav can take care of it.
// if (formControlType == NS_FORM_SELECT)
// return NS_OK;

aEvent->StopPropagation();// We're using this key, no one else should
aEvent->PreventDefault();
returnDown();
}

returnNS_OK;
}

以上函数负责对按键事件的处理。我发现该函数被调用了,但是就是没有切换焦点,调试了好一会才发现,原来是两个设置没有设,后来加了一个函数,在初始时调用,一切正常了:

gboolean mozilla_pref_init(void)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);

if(NS_SUCCEEDED(rv) && pref != nsnull)
{
pref->SetIntPref("snav.keyCode.modifier", 0);
pref->SetBoolPref("snav.enabled", true);
}

return TRUE;
}

Spatialnavigation是一个非常典型的扩展,对于实现自己的扩展很有参考价值,特别是添加自己的快捷键处理。

~~end~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值