2012-03-12 81 views
7

我正在为android 2.2及更高版本创建softkeyboard。一切都很好,但是当我输入真的很快,然后有一段时间我的ACTION_DOWN方法没有调用。调用方法的实际流量应该像SoftKeyboard for android

    1) motionEvent.ACTION_DOWN 
        2) OnPress() 
        3) motionEvent.ACTION_UP 
        4) OnRelease() and repeat same order for next word. 

,如果我以正常速度类型,然后它工作正常,但如果我输入快则上述方法执行的顺序看起来像

    1) motionEvent.ACTION_DOWN 
       2) OnPress() 
       3) OnRelease() 
       4) motionEvent.ACTION_UP and for next word OnPress and OnRelease() methods are being called. 

有什么建议?

编辑 包含MotionActionEvents

enter code here @Override 
public boolean onTouchEvent(MotionEvent me) { 
    // Moved next line and added lines to help solve reentrant problem. 
    int action = me.getAction(); 
    // next 2 lines required for multitouch Andr 2+ 
    int act = action & MotionEvent.ACTION_MASK; 
    final int ptrIndex = (act & MotionEvent.ACTION_POINTER_ID_MASK) //Renamed to ACTION_POINTER_INDEX_MASK in later Andro versions 
    >> MotionEvent.ACTION_POINTER_ID_SHIFT;//Renamed to ACTION_POINTER_INDEX_SHIFT in later Andro versions 

//  currentX = me.getX(); 
//  currentY = me.getY(); 
     calcMinSlide(); 

//  int act = me.getAction(); 
     if (act == android.view.MotionEvent.ACTION_DOWN) { 
      Log.v(tag, "ANGLE_ACTION_DOWN : "); 


     if (pw != null) { 
      pw.dismiss(); 
      pw = null; 
     } 
     lastDirection = direction = 0; 
     touchDownPoint.set(me.getX(), me.getY()); 

     // Will added next two lines 
     touchDragPoint.set(me.getX(), me.getY()); 
     thresholdPoint.set(me.getX(), me.getY()); 
     // Will6 added to improve accuracy 
     thresholdPoint1_5 = false; 
     // Will7 added next 4 for Andro 2+ 
     currentX = me.getX(); 
     currentY = me.getY(); 
     // Save the ID of this first pointer (touch) down 
     currentPointerID = me.getPointerId(0); 
     nextPointerID = INVALID_POINTER_ID; 

     previousDownTime = me.getEventTime(); 
     me.setLocation(touchDownPoint.x, touchDownPoint.y); 
     // start timer on touch down 
     startTimer(me, 300); // 150); Will7 changed this and removed method: checkLongPress 

    } else if (act == android.view.MotionEvent.ACTION_UP 
       || act == android.view.MotionEvent.ACTION_MOVE) { 

     Log.v(tag, "ANGLE_ACTION_UP : "); 
     //touchdragPoint and previoustouchPoint for calculating velocity 
     PointF previousTouchPoint = new PointF(touchDragPoint.x,touchDragPoint.y); 

     //Will7 added next if for Andro 2+: Find the index of the active pointer and fetch its position 
     if (act == android.view.MotionEvent.ACTION_MOVE && me.getPointerId(ptrIndex) != currentPointerID) { 
      //Log.v(tag, "Cancel ATION_MOVE!! ID: "+me.getPointerId(ptrIndex)); 
      return super.onTouchEvent(me); 
     } 
     touchDragPoint.set(me.getX(), me.getY());   
     dy = me.getY() - touchDownPoint.y; 
     dx = me.getX() - touchDownPoint.x; 

     // added for Andro 2+ 
     currentX = touchDragPoint.x; 
     currentY = touchDragPoint.y; 

     //calculate time interval from down time to current time 
     long timeInterval = me.getEventTime() - previousDownTime; 
     previousDownTime = me.getEventTime(); 
     velocityThresDir = VELOCITY_THRESHOLD; 
     float touchVelocity = Math.abs(distanceBetweenPoints(touchDragPoint, previousTouchPoint)/timeInterval); 

     if (distanceFromCenter(dx,dy) > minSlide) { 
//    Log.v(tag, "direction to detect angle....after... dx..."+dx+" dy "+dy); 
       //Log.v(tag, "ANGLE angle.... after..."+distanceFromCenter(dx,dy)+" slide distance "+ minSlide); 


      /* cancel the timer*/ 
      if (cDownTimer != null) { 
       cDownTimer.cancel(); 
       cDownTimer = null; 
      } 
      /* coding for calculating velocity threshold*/   
      float angleThreshold = 0.0f; 
      if ((thresholdPoint.x == touchDownPoint.x) && (thresholdPoint.y == touchDownPoint.y)){ 
       thresholdPoint.set(touchDragPoint.x, touchDragPoint.y); 
      } 
      else { 
       //Will6 - added next if to improve accuracy 
       if ((distanceFromCenter(dx,dy) > (minSlide * 1.5)) && !thresholdPoint1_5){ 
        thresholdPoint.set(me.getX(),me.getY()); 
        thresholdPoint1_5 = true; 
       } 
       float angleP1= calcAngle(touchDownPoint, thresholdPoint); 
       float angleP2= calcAngle(previousTouchPoint, touchDragPoint); 
       angleThreshold = Math.abs(angleP1 - angleP2); 
       if (angleThreshold > Math.PI) angleThreshold = (float) (2.0 * Math.PI) - angleThreshold; 
      } 
//    velocityThresDir = (float) Math.abs((Math.cos(angleThreshold) * touchVelocity*1000)); 
       velocityThresDir = (float) (Math.cos(angleThreshold) * touchVelocity*1000); 

      //end of calculation for velocity threshold 


      double angle = newM(touchDownPoint.x, touchDownPoint.y, touchDragPoint.x, touchDragPoint.y); 
//    Log.v(tag, "ANGLE_FIRST_X "+touchDownPoint.x+"FIRST_Y "+touchDownPoint.y); 
//    Log.v(tag, "ANGLE_SECOND_X "+touchDragPoint.x+"SECOND_Y "+touchDragPoint.y); 
//    Log.v(tag, "ANGLE_FIRST"+angle); 

      if ((touchDownPoint.x != thresholdPoint.x) || (touchDownPoint.y != thresholdPoint.y)) { 
       double angleThresh = newM(touchDownPoint.x, touchDownPoint.y, thresholdPoint.x, thresholdPoint.y); 
       double angleBetween = Math.abs(angle - angleThresh); 
       if(angleBetween < 45 || angleBetween > 315){ 
        if(angleBetween > 315) { 
         if (angle < angleThresh) { 
          angle += 360; 
         } 
         else if (angle > angleThresh) { 
          angleThresh += 360; 
         } 
         angle = Math.abs((angle - angleThresh)%360)/2.0; 
//       Log.v(tag, "ANGLE_SECOND"+angle); 
         } 
         else { 
          angle = (angle + angleThresh * 1.0)/2.0; 
//       Log.v(tag, "ANGLE_THIRD"+angle); 
         } 
        } 
       } 

      if (angle > 337.5){ 
       direction = 3; 
      }else if (angle > 292.5){ 
       direction = 5; 
      }else if (angle > 247.5){ 
       direction = 4; 
      }else if (angle > 202.5){ 
       direction = 6; 
      }else if (angle > 157.5){ 
       direction = 1; 
      }else if (angle > 112.5){ 
       direction = 7; 
      }else if (angle > 67.5){ 
       direction = 2; 
      }else if (angle > 22.5){ 
       direction = 8; 
      }else{ 
       direction = 3; 
      } 

      /* start timer if velocity is below velocity threshold*/  
      if ((velocityThresDir < VELOCITY_THRESHOLD) && 
        (act == android.view.MotionEvent.ACTION_MOVE) && (cDownTimer == null) && 
        (pw == null)) { //"&& cDownTimer" can be removed I think 
       /* start timer with motionEvent and time in ms as a parameter */ 
       // added next two lines 
       callOnLongPress(me); 
       startTimerShowPopup(me,100);//Will changed from 150 
      }   
     } else { 
      direction = 0; 
     } 

     if (act == android.view.MotionEvent.ACTION_MOVE) { 
      return true; 
     } else if (act == android.view.MotionEvent.ACTION_UP) { 
      if (cDownTimer != null) { 
       cDownTimer.cancel(); 
       cDownTimer = null; 
      } 
      if (pw != null) 
       pw.dismiss(); 
      if (longPressedKey) { 
       SoftKeyboard.mComposing 
         .append(charset[mappedKey][direction]); 
       popUpTextEntryScheme = true; 
      } 

      longPressedKey = false; 
      currentPointerID = INVALID_POINTER_ID; 
     } 
    } 

    else if (act == android.view.MotionEvent.ACTION_POINTER_DOWN) { 
     //   if (me.getPointerCount() > 1) { //Should always be true, I think 
      nextPointerID = me.getPointerId(ptrIndex); 
      nextTouchDownPoint.set(me.getX(ptrIndex),me.getY(ptrIndex)); 
//   } 
     } 
     else if (act == android.view.MotionEvent.ACTION_CANCEL) { 
      currentPointerID = INVALID_POINTER_ID; 
      nextPointerID = INVALID_POINTER_ID; 

    } 
    else if (act == android.view.MotionEvent.ACTION_POINTER_UP) { 
     // Extract the index of the pointer that left the touch sensor 
     final int pointerId = me.getPointerId(ptrIndex); 
     if (pointerId == currentPointerID) { 
      // This was our active pointer going up. Choose a new 
      // active pointer and adjust accordingly. 
      final int newPointerIndex = ptrIndex == 0 ? 1 : 0; 
      currentPointerID = nextPointerID;//(0); 
      touchDownPoint.set(nextTouchDownPoint.x,nextTouchDownPoint.y); 
      if (cDownTimer != null) { 
       cDownTimer.cancel(); 
       cDownTimer = null; 
      } 
      if (pw != null) { 
       pw.dismiss(); 
       pw = null; 
      } 
      if (longPressedKey) { 
       SoftKeyboard.mComposing 
         .append(charset[mappedKey][direction]); 
       popUpTextEntryScheme = true; 
      } 
      longPressedKey = false; 
      lastDirection = direction = 0; // keysAtOnce=0; 

      touchDragPoint.set(me.getX(newPointerIndex),me.getY(newPointerIndex)); 
      thresholdPoint.set(nextTouchDownPoint.x,nextTouchDownPoint.y); 
      //added to improve accuracy 
      thresholdPoint1_5 = false; 
      // added next 3 for Andro 2+ 
      currentX = touchDragPoint.x; 
      currentY = touchDragPoint.y; 
      // Save the ID of this first pointer (touch) down 

      previousDownTime = me.getEventTime(); 
      me.setLocation(touchDownPoint.x, touchDownPoint.y); 
      //start timer on touch down  
      startTimer(me,300); //150); Will7 changed this and removed method: checkLongPress 
     } else { //Second pointer up before first. (Not handling 3 or more pointers yet!) 

//    nextPointerID = INVALID_POINTER_ID; 
      } 
     } //else 



    return super.onTouchEvent(me); // after we return here the service will get notified, etc 
//  return true; 
    } 

和我SoftKeyboard类我LatinKeyboardView类..

public void onPress(int primaryCode) { 
     Log.v("SoftKeyboard", "ANGLE_ACTION_ON_PRESS : "); 

     // added next section for repeating backspace 
     if (RepeatBSTimer != null) { 
      RepeatBSTimer.cancel(); 
      RepeatBSTimer = null; 
     } 
     if (mp != null) { // /Will7 moved this from just above keystroke 
          // statement 
      mp.release(); 
      mp = null; 
     } 

     // added for Andro 2+ multitouch 
     if (primaryCode == pressedCode 
       && LatinKeyboardView.nextPointerID != LatinKeyboardView.INVALID_POINTER_ID) { 
      // I need to look up the real primaryCode here. (Not sure how!) 
      // Android gives wrong values when touches overlap. 
      wrongPrimaryCode = true; 
      return; 
     } else 
      wrongPrimaryCode = false; 

     pressedCode = primaryCode; 

     // added next section for repeating backspace 
     if (primaryCode == Keyboard.KEYCODE_DELETE) { 
      RepeatBSTimer = new CountDownTimer(1500000, 75) { 
       @Override 
       public void onTick(long millisUntilFinished) { 
        int primaryCode2; 
        if (LatinKeyboardView.longPressedKey 
          || (1500000 - millisUntilFinished > 500)) { 
         primaryCode2 = getCharFromKey(pressedCode, 
           LatinKeyboardView.direction, mInputView 
             .getKeyboard()); 
         if (primaryCode2 == Keyboard.KEYCODE_DELETE) { 
          repeating = true; 
          handleBackspace(); 
         } else if (primaryCode2 == KEYCODE_DELETEWORD 
           && (millisUntilFinished % 150) < 75) { 
          repeating = true; 
          deleteLastWord(); 
         } 
        } 
       } 

       @Override 
       public void onFinish() { 
       } 
      }; 
      RepeatBSTimer.start(); 
     } 
     // added section for repeating backspace 

     Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" 
       + R.raw.keystroke);// Play Key Click 
     try { 
      mp = new MediaPlayer(); 
      mp.setDataSource(this, uri); 
      mp.prepare(); 
      mp.start(); 
     } catch (IllegalArgumentException e) { 
      e.printStackTrace(); 
     } catch (SecurityException e) { 
      e.printStackTrace(); 
     } catch (IllegalStateException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
} 

public void onRelease(int primaryCode) { 

     // Will7 added next line if for Andro 2+ multitouch 
     if (wrongPrimaryCode 
       && LatinKeyboardView.nextPointerID != LatinKeyboardView.INVALID_POINTER_ID) { 

      return; 
     } 
     // else pressedCode = primaryCode; 


     // added next sections for repeating backspace 
     primaryCode = getCharFromKey(pressedCode, LatinKeyboardView.direction,mInputView.getKeyboard()); 
     if (primaryCode == Keyboard.KEYCODE_DELETE && !repeating) 
      handleBackspace(); 
     if (primaryCode == KEYCODE_DELETEWORD && !repeating) 
      deleteLastWord(); 
     repeating = false; 

     if (RepeatBSTimer != null) { 
      RepeatBSTimer.cancel(); 
      RepeatBSTimer = null; 
     } 
     // moved all the rest of this method from onKey() 
     int[] keyCodes; 

     // added this var for Andro 2+ multitouch 
     keyCodes = keyCodesSave; 

     commitTyped(getCurrentInputConnection()); 


     if (isWordSeparator(primaryCode) && (char) primaryCode != '.' 

       && (char) primaryCode != '!' && (char) primaryCode != '?') { 
      // Handle separator 
      if (mComposing.length() > 0) { 
       commitTyped(getCurrentInputConnection()); 
      } 
      sendKey(primaryCode); 
      updateShiftKeyState(getCurrentInputEditorInfo()); 
     } else if (primaryCode == Keyboard.KEYCODE_DELETE) { 
      // commented out next line for repeating backspace 
      // handleBackspace(); 
     } else if (primaryCode == Keyboard.KEYCODE_SHIFT || primaryCode == -1) { 
      handleShift(); 
     } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { 
      handleClose(); 
      return; 
     } else if (primaryCode == KEYCODE_ESCAPE) { 
      // Do nothing on Escape key 
     } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) { 
      // Show a menu or something 
     } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE 
       && mInputView != null) { 
      Keyboard current = mInputView.getKeyboard(); 
      if (current == mSymbolsKeyboard 
        || current == mSymbolsShiftedKeyboard) { 
       getCurrentInputConnection().finishComposingText(); 
       current = mQwertyKeyboard; 
      } else { 
       getCurrentInputConnection().finishComposingText(); 
       current = mSymbolsKeyboard; 
      } 
      mInputView.setKeyboard(current); 
      if (current == mSymbolsKeyboard) { 
       current.setShifted(false); 
      } 
     } else if (primaryCode == KEYCODE_CAPSLOCK)// handle caps lock 
     { 
      if (mInputView.getKeyboard() == mQwertyKeyboard 
        || mInputView.getKeyboard() == mSymbolsKeyboard) { 
       mInputView.setKeyboard(mQwertyKeyboardUpperCase); 
       mQwertyKeyboardUpperCase.setShifted(true); 
       mCapsLock = true; 
      } else { 
       mQwertyKeyboard.setShifted(false); 
       mInputView.setKeyboard(mQwertyKeyboard); 
       mCapsLock = false; 
      } 
     } else if (primaryCode == KEYCODE_DELETEWORD) { 
      // commented out next line for repeating backspace 
      // deleteLastWord(); 
     } else if (primaryCode == KEYCODE_FULL_STOP_AND_SPACE) { 
      // added next line 
      backspaceIfSpaceLeft(); 
      getCurrentInputConnection().finishComposingText(); 

      handleCharacter((int) '.', keyCodes); 
      handleCharacter((int) ' ', keyCodes); 
      handleShift(); 

     } 
     // added next 5 KEYCODES 
     else if (primaryCode == KEYCODE_EXCLAMATION) { 
      // added next line 
      backspaceIfSpaceLeft(); 
      getCurrentInputConnection().finishComposingText(); 

      handleCharacter((int) '!', keyCodes); 
      handleCharacter((int) ' ', keyCodes); 
      handleShift(); 

     } else if (primaryCode == KEYCODE_QUESTION_MARK) { 
      // added next line 
      backspaceIfSpaceLeft(); 
      getCurrentInputConnection().finishComposingText(); 

      handleCharacter((int) '?', keyCodes); 
      handleCharacter((int) ' ', keyCodes); 
      handleShift(); 

     } else if (primaryCode == KEYCODE_COMMA) { 
      // added next line 
      backspaceIfSpaceLeft(); 
      getCurrentInputConnection().finishComposingText(); 

      handleCharacter((int) ',', keyCodes); 
      handleCharacter((int) ' ', keyCodes); 

     } else if (primaryCode == KEYCODE_COLON) { 
      // added next line 
      backspaceIfSpaceLeft(); 
      getCurrentInputConnection().finishComposingText(); 

      handleCharacter((int) ':', keyCodes); 
      handleCharacter((int) ' ', keyCodes); 

     } else if (primaryCode == KEYCODE_SEMICOLON) { 
      // added next line 
      backspaceIfSpaceLeft(); 
      getCurrentInputConnection().finishComposingText(); 

      handleCharacter((int) ';', keyCodes); 
      handleCharacter((int) ' ', keyCodes); 

     } else { 
      handleCharacter(primaryCode, keyCodes); 
     } 
} 

谢谢..

+2

没有看到你的代码没有人可以建议你任何东西,所以张贴主要部分的代码... – himanshu 2012-03-22 05:50:00

回答

2

这是一个很长的onTouchEvent处理,我建议将其分成多个逻辑步骤。尝试处理触摸屏时,我也遇到了看似“无序”事件的问题。

我发现我没有正确处理每个指针ID的事件。我会检查以确保您按预期处理多个指针。我用(N1)测试的设备只支持两个指针,但其他支持更多,这些都应该考虑在内。

对于处理触摸屏“软按钮”作为onTouchEvent事件,我发现创建状态机类很有用。使用参数MotionEvent作为状态机的输入事件,并使状态转换触发你想要的事件。一个明确的,由国家驱动的方法会给你预期的结果,你正在寻找。