幻想小说网 酷文学 深夜书屋 叮当小说网 找小说网 无限小说网 红尘小说网

在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))
    return rv;  
  
  target->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
                                  static_cast<nsIDOMKeyListener*>(this),
                                  PR_FALSE,
                                  systemGroup);
  
  return NS_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)
    return NS_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)
      return NS_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)
    return NS_ERROR_FAILURE;
  
  nsCOMPtr<nsIDOMEventTarget> domEventTarget;
  nsEvent->GetOriginalTarget(getter_AddRefs(domEventTarget));
  
  nsCOMPtr<nsIContent> targetContent = do_QueryInterface(domEventTarget);

  if (targetContent->IsNodeOfType(nsINode::eXUL))
    return NS_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)
        {
          return NS_OK;
        }
      }
  }
  else if (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"))
        return NS_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)
        return NS_OK;
    }

    // We're using this key, no one else should
    aEvent->StopPropagation();
        aEvent->PreventDefault();
        
    return Left();
  }
  
  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)
        return NS_OK;
    }
        
    aEvent->StopPropagation();
        aEvent->PreventDefault();
    return Right();
  }
  
  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();
    return Up();
  }
  
  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();
    return Down();
  }
  
  return NS_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~~

 

posted on 2007-08-07 21:22  张云临  阅读(152)  评论(0编辑  收藏  举报

导航