soft keyboard and `textInputNotRequired'

For Android specific issues

soft keyboard and `textInputNotRequired'

Postby hugh » Sat Jun 09, 2012 12:11 am

i'm trying to implement the popup soft keyboard on android. this needs to be triggered from the ComponentPeer. so by implementing `textInputRequired' inside juce_android_Windowing.cpp i can get a keyboard to appear. but then i have no way to remove it. at first, i thought i could hook `dismissPendingTextInput' but this is not called when there is no "pending text input", for example if you don't make an edit to a box.

i put a bit of a hack into my version as follows;

i added virtual void ComponentPeer::textInputNotRequired(); and then implemented this in juce_android_Windowing.cpp

right now i'm triggering this from the Label

Code: Select all
void Label::editorAboutToBeHidden (TextEditor*)
{
    ComponentPeer* const peer = getPeer();
    if (peer)
        peer->textInputNotRequired();
}


probably not the ideal place, but it gets there.


here's also the code to do the soft keyboard,

juce_android_Windowing.cpp:

Code: Select all
void textInputRequired (const Point<int>& position)
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, true);
    }

    void textInputNotRequired ()
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, false);
    }

   void dismissPendingTextInput()
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, false);
    }



Java activity,

Code: Select all
import android.view.inputmethod.InputMethodManager;

     public void showKeyboard(boolean v)
        {
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            if (v)
                imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
            else
                imm.hideSoftInputFromWindow(getWindowToken(), 0);
        }


There are probably many problems left with this. firstly, forcing the keyboard on and off is probably not the best way and secondly, i'm not yet checking for the existence of a real keyboard.

also, it's still wobbly. the keyboard can keep popping up and down if you've got a panel with several entry boxes. not ideal.

-- hugh.
User avatar
hugh
JUCE UberWeenie
 
Posts: 174
Joined: Sun Apr 25, 2010 8:04 pm
Location: London, UK

Re: soft keyboard and `textInputNotRequired'

Postby bebopagogo » Fri Aug 24, 2012 5:18 pm

Did you add your Java activity code as a method of the "JuceAppActivity" class? Or extend that class in some other way? (i.e. without modifying the "JuceAppActivity.java" file). I'm not a big Java jockey but the "final" keyword on JuceAppActivity may not let you extend it. I'm just looking at adding your ideas here to an app that needs keyboard popup / popdown and just trying to figure out how to proceed in a pragmatic way (given my newness to Android and Juce). For example, in IOS, I was able able add some C++/Objective C to inform the main window when the keyboard popped up/down and the keyboard size so the window could resize itself so the keyboard didn't hide it. I'm trying to figure out how to do the same for Android and your code here looks like a place to start (So thanks for posting this in the first place!)
bebopagogo
User avatar
bebopagogo
JUCE Weenie
 
Posts: 3
Joined: Thu Mar 15, 2012 2:08 am

Re: soft keyboard and `textInputNotRequired'

Postby hugh » Fri Aug 24, 2012 5:50 pm

Hello, i've been using this juce hack for a while now and it's mostly ok.

Yes, there are some other boring changes to make it work, i skipped over. let me see....


juce_ComponentPeer.h
Code: Select all
// any OS keyboard not required
    virtual void textInputNotRequired () {}


juce_android_windowing.cpp. note the hacks to the key codes. i've only fixed a few of them so that the basics work.

Code: Select all
*** 91,102 ****
--- 94,106 ----
   METHOD (requestFocus,  "requestFocus",     "()Z") \
   METHOD (setVisible,    "setVisible",       "(Z)V") \
   METHOD (isVisible,     "isVisible",        "()Z") \
   METHOD (hasFocus,      "hasFocus",         "()Z") \
   METHOD (invalidate,    "invalidate",       "(IIII)V") \
   METHOD (containsPoint, "containsPoint",    "(II)Z") \
+  METHOD (showKeyboard, "showKeyboard",      "(Z)V") \
   METHOD (createGLView,  "createGLView",     "()L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$OpenGLView;") \
 
  DECLARE_JNI_CLASS (ComponentPeerView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView");
  #undef JNI_CLASS_MEMBERS
 
 
***************
*** 353,364 ****
--- 357,379 ----
      {
          lastMousePos.setXY ((int) x, (int) y);
          currentModifiers = currentModifiers.withoutMouseButtons();
          handleMouseEvent (0, lastMousePos, currentModifiers, time);
      }
 
+     void handleKeyDownCallback (int k, int kc)
+     {
+         handleKeyPress(k, kc);
+     }
+
+     void handleKeyUpCallback (int k, int kc)
+     {
+         //handleKeyUpOrDown(false);
+     }
+
+
      //==============================================================================
      bool isFocused() const
      {
          return view.callBooleanMethod (ComponentPeerView.hasFocus);
      }
 
***************
*** 374,386 ****
          else
              handleFocusLoss();
      }
 
      void textInputRequired (const Point<int>& position)
      {
!         // TODO
      }
 
      //==============================================================================
      void handlePaintCallback (JNIEnv* env, jobject canvas)
      {
          jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
--- 389,411 ----
          else
              handleFocusLoss();
      }
 
      void textInputRequired (const Point<int>& position)
      {
!         view.callVoidMethod (ComponentPeerView.showKeyboard, true);
!     }
!
!     void textInputNotRequired ()
!     {
!         view.callVoidMethod (ComponentPeerView.showKeyboard, false);
!     }
!
!     void dismissPendingTextInput()
!     {
!         view.callVoidMethod (ComponentPeerView.showKeyboard, false);
      }
 
      //==============================================================================
      void handlePaintCallback (JNIEnv* env, jobject canvas)
      {
          jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
***************
*** 557,568 ****
--- 582,597 ----
  JUCE_VIEW_CALLBACK (void, handleMouseDown,  (JNIEnv* env, jobject view, jfloat x, jfloat y, jlong time),    handleMouseDownCallback ((float) x, (float) y, (int64) time))
  JUCE_VIEW_CALLBACK (void, handleMouseDrag,  (JNIEnv* env, jobject view, jfloat x, jfloat y, jlong time),    handleMouseDragCallback ((float) x, (float) y, (int64) time))
  JUCE_VIEW_CALLBACK (void, handleMouseUp,    (JNIEnv* env, jobject view, jfloat x, jfloat y, jlong time),    handleMouseUpCallback ((float) x, (float) y, (int64) time))
  JUCE_VIEW_CALLBACK (void, viewSizeChanged,  (JNIEnv* env, jobject view),                                    handleMovedOrResized())
  JUCE_VIEW_CALLBACK (void, focusChanged,     (JNIEnv* env, jobject view, jboolean hasFocus),                 handleFocusChangeCallback (hasFocus))
 
+ JUCE_VIEW_CALLBACK (void, handleKeyDown,  (JNIEnv* env, jobject view, jint k, jint kc),  handleKeyDownCallback ((int) k, (int)kc))
+
+ JUCE_VIEW_CALLBACK (void, handleKeyUp,  (JNIEnv* env, jobject view, jint k, jint kc),  handleKeyUpCallback ((int) k, (int)kc))
+
  //==============================================================================
  ComponentPeer* Component::createNewPeer (int styleFlags, void*)
  {
      return new AndroidComponentPeer (*this, styleFlags);
  }
 
***************
*** 621,637 ****
 
  //==============================================================================
  bool Process::isForegroundProcess()
  {
      return true;      // TODO
  }
-
  void Process::makeForegroundProcess()
  {
  }
-
  //==============================================================================
  void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
                                                            const String& title, const String& message,
                                                            Component* associatedComponent)
  {
      android.activity.callVoidMethod (JuceAppActivity.showMessageBox, javaString (title).get(), javaString (message).get(), (jlong) 0);
--- 650,664 ----
***************
*** 752,778 ****
      return juceString (text);
  }
 
  //==============================================================================
  const int extendedKeyModifier       = 0x10000;
 
  const int KeyPress::spaceKey        = ' ';
! const int KeyPress::returnKey       = 0x0d;
! const int KeyPress::escapeKey       = 0x1b;
! const int KeyPress::backspaceKey    = 0x7f;
  const int KeyPress::leftKey         = extendedKeyModifier + 1;
  const int KeyPress::rightKey        = extendedKeyModifier + 2;
  const int KeyPress::upKey           = extendedKeyModifier + 3;
  const int KeyPress::downKey         = extendedKeyModifier + 4;
  const int KeyPress::pageUpKey       = extendedKeyModifier + 5;
  const int KeyPress::pageDownKey     = extendedKeyModifier + 6;
  const int KeyPress::endKey          = extendedKeyModifier + 7;
  const int KeyPress::homeKey         = extendedKeyModifier + 8;
  const int KeyPress::deleteKey       = extendedKeyModifier + 9;
  const int KeyPress::insertKey       = -1;
! const int KeyPress::tabKey          = 9;
  const int KeyPress::F1Key           = extendedKeyModifier + 10;
  const int KeyPress::F2Key           = extendedKeyModifier + 11;
  const int KeyPress::F3Key           = extendedKeyModifier + 12;
  const int KeyPress::F4Key           = extendedKeyModifier + 13;
  const int KeyPress::F5Key           = extendedKeyModifier + 14;
  const int KeyPress::F6Key           = extendedKeyModifier + 16;
--- 779,810 ----
      return juceString (text);
  }
 
  //==============================================================================
  const int extendedKeyModifier       = 0x10000;
 
+     const int KeyPress::returnKey       = 66;
+     const int KeyPress::escapeKey       = 4;
+     const int KeyPress::backspaceKey    = 67;
+     const int KeyPress::tabKey          = 61;
+
  const int KeyPress::spaceKey        = ' ';
!     //const int KeyPress::returnKey       = 0x0d;
!     //const int KeyPress::escapeKey       = 0x1b;
!     //const int KeyPress::backspaceKey    = 0x7f;
  const int KeyPress::leftKey         = extendedKeyModifier + 1;
  const int KeyPress::rightKey        = extendedKeyModifier + 2;
  const int KeyPress::upKey           = extendedKeyModifier + 3;
  const int KeyPress::downKey         = extendedKeyModifier + 4;
  const int KeyPress::pageUpKey       = extendedKeyModifier + 5;
  const int KeyPress::pageDownKey     = extendedKeyModifier + 6;
  const int KeyPress::endKey          = extendedKeyModifier + 7;
  const int KeyPress::homeKey         = extendedKeyModifier + 8;
  const int KeyPress::deleteKey       = extendedKeyModifier + 9;
  const int KeyPress::insertKey       = -1;
!     //const int KeyPress::tabKey          = 9;
  const int KeyPress::F1Key           = extendedKeyModifier + 10;
  const int KeyPress::F2Key           = extendedKeyModifier + 11;
  const int KeyPress::F3Key           = extendedKeyModifier + 12;
  const int KeyPress::F4Key           = extendedKeyModifier + 13;
  const int KeyPress::F5Key           = extendedKeyModifier + 14;
  const int KeyPress::F6Key           = extendedKeyModifier + 16;


There are some changes you have to make also to your generated java activity class:

Code: Select all
import android.view.inputmethod.InputMethodManager;
...
      private native void handleKeyDown (int keycode, int textchar);
        private native void handleKeyUp (int keycode, int textchar);


        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event)
        {
         
            handleKeyDown(keyCode, event.getUnicodeChar());
            return true;
        }   

        @Override
        public boolean onKeyUp(int keyCode, KeyEvent event)
        {
            handleKeyUp(keyCode, event.getUnicodeChar());
            return true;
        }   

        public void showKeyboard(boolean v)
        {
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            if (v)
                imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
            else
                imm.hideSoftInputFromWindow(getWindowToken(), 0);
        }


i think that might be it,

-- hugh.
User avatar
hugh
JUCE UberWeenie
 
Posts: 174
Joined: Sun Apr 25, 2010 8:04 pm
Location: London, UK

Re: soft keyboard and `textInputNotRequired'

Postby spaky » Wed Nov 21, 2012 3:00 pm

Hey,

i also tried to get the soft keyboard working on Samsung Galaxy Tab2 10.1 with Android 4.03.

Following things I needed to add in addition to yours:

Code: Select all
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager


Code: Select all
        @Override
        public InputConnection onCreateInputConnection(EditorInfo outAttrs)
        {
            outAttrs.actionLabel = "";
            outAttrs.hintText = "";
            outAttrs.initialCapsMode = 0;
            outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
            outAttrs.label = "";
            outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;       
            outAttrs.inputType = InputType.TYPE_NULL;       

            return  new BaseInputConnection(this, false);       
        }
spaky
JUCE Weenie
 
Posts: 4
Joined: Fri Jun 22, 2007 9:56 am

Re: soft keyboard and `textInputNotRequired'

Postby hugh » Wed Nov 21, 2012 6:23 pm

Hi,

Thanks for the additions. i've not tried in on the samsung tab (nor other samsungs). i've tried the nexus7 (4.2) and a no-name gingerbread 2.3.3 phone.
User avatar
hugh
JUCE UberWeenie
 
Posts: 174
Joined: Sun Apr 25, 2010 8:04 pm
Location: London, UK

Re: soft keyboard and `textInputNotRequired'

Postby jules » Thu Nov 22, 2012 6:44 pm

I should add this stuff.. Hugh, could you perhaps mail me a copy of whatever your latest files are so I can have a shufty at the changes? Ta!
User avatar
jules
Fearless Leader
 
Posts: 17218
Joined: Mon Sep 06, 2004 9:03 am
Location: London, UK

Re: soft keyboard and `textInputNotRequired'

Postby hugh » Thu Nov 22, 2012 7:32 pm

will do. i'll send you a changelist against the latest juce tip.

-- hugh.
User avatar
hugh
JUCE UberWeenie
 
Posts: 174
Joined: Sun Apr 25, 2010 8:04 pm
Location: London, UK

Re: soft keyboard and `textInputNotRequired'

Postby Nogoth » Tue May 14, 2013 10:16 am

I'm asking here to not open new topic. I am writing app and I need software keyboard. In landscape view everything is ok (I'm testing ok Galaxy Mini II), but in portrait it looks like something is covering keyboard. Do You know how to fix it?
Nogoth
JUCE Weenie
 
Posts: 3
Joined: Tue Apr 30, 2013 5:01 pm


Return to Android

Who is online

Users browsing this forum: No registered users and 2 guests