Bigfoot71 / raymob

Simple raylib implementation for Android
Other
86 stars 19 forks source link

How do you get keyboard input? #5

Closed NerdyPuzzle closed 1 year ago

NerdyPuzzle commented 1 year ago

Not really an issue, but rather a question. How can I get character input through the android keyboard? Could you maybe include some functions for keyboard input?

Bigfoot71 commented 1 year ago

Thank you, that's a very good question. Unfortunately, using the software keyboard in a native application is not a straightforward task to implement.

I've done quite a few tests on my end, and there are functions like ANativeActivity_showSoftInput and ANativeActivity_hideSoftInput that are supposed to simplify the task, but they don't seem to work in our case.

The simplest way to get the keyboard would be to add the following code to the Java class NativeLoader:

/* ... */

import android.view.inputmethod.InputMethodManager;
import android.content.Context;

/* ... */

public class NativeLoader extends NativeActivity {

    /* ... */

    public void showKeyboard()
    {
        InputMethodManager imm = ( InputMethodManager )getSystemService( Context.INPUT_METHOD_SERVICE );
        imm.showSoftInput( this.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED );
    }

    public void hideKeyboard()
    {
        InputMethodManager imm = ( InputMethodManager )getSystemService( Context.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( this.getWindow().getDecorView().getWindowToken(), 0 );
    }

    /* ... */

}

And call them like this from C/C++ (example written in C):

void ShowKeyboard(void)
{
    jobject nativeLoaderInstance = GetNativeLoaderInstance();

    if (nativeLoaderInstance != NULL)
    {
        JNIEnv* env = AttachCurrentThread();

        jclass nativeLoaderClass = (*env)->GetObjectClass(env, nativeLoaderInstance);
        jmethodID showKeyboardMethod = (*env)->GetMethodID(env, nativeLoaderClass, "showKeyboard", "()V");

        if (showKeyboardMethod != NULL)
        {
            (*env)->CallVoidMethod(env, nativeLoaderInstance, showKeyboardMethod);
        }

        DetachCurrentThread();
    }
}

void HideKeyboard(void)
{
    jobject nativeLoaderInstance = GetNativeLoaderInstance();

    if (nativeLoaderInstance != NULL)
    {
        JNIEnv* env = AttachCurrentThread();

        jclass nativeLoaderClass = (*env)->GetObjectClass(env, nativeLoaderInstance);
        jmethodID hideKeyboardMethod = (*env)->GetMethodID(env, nativeLoaderClass, "hideKeyboard", "()V");

        if (hideKeyboardMethod != NULL)
        {
            (*env)->CallVoidMethod(env, nativeLoaderInstance, hideKeyboardMethod);
        }

        DetachCurrentThread();
    }
}

This will display the Android software keyboard, but then you need to find the right way to capture keyboard events, which is a bit more technical. I won't go into the details, but the cleanest way to do it would be to rewrite a fair amount of code in rcore.c.

https://github.com/Bigfoot71/Raymob/assets/90587919/56902be3-8200-4a4f-96d6-7e686154fa5f

I'm still thinking about it because I'd like to integrate all these features (like vibration, accelerometer, microphone, camera, software keyboard, etc.) not directly into raymob but into a separate module that would contain a C header linked to a Java class and be modular. However, it's challenging to do without touching rcore.c; it requires a lot of work and thought on implementation.

If you have any ideas/suggestions, I would certainly appreciate them!

NerdyPuzzle commented 1 year ago

You could maybe initialize a KeyEvent class when the app boots up, then modify the GetCharsPressed() or whatever it's called function in raylib to return characters from the onKeyUp callback? I don't know if that's the right class for software keyboard input, but if it's not, I'm sure you can find it with some digging.

Bigfoot71 commented 1 year ago

Thank you for your suggestion. I've started a major refactoring work that will include everything I've presented (including the soft keyboard).

It's going to be a lot of work. Feel free to close the issue or not if you want to be informed when all these additions are pushed to the repository. I will close it myself at that time with a message.

Thanks again for submitting the idea, it's the kind of thing I can be very slow to do on my own if I don't see anyone asking for it ^^

Bigfoot71 commented 1 year ago

I just committed the addition of a very basic feature for the Android software keyboard!

To use it, you can simply set the features.soft_keyboard value in the gradle.properties file to true and replace #include "raylib.h" with #include "raymob.h" to access the additional functions.

Here is the current list of functions for the keyboard:

void ShowSoftKeyboard(void);
void HideSoftKeyboard(void);
bool IsSoftKeyboardActive(void);
int GetLastSoftKeyCode(void);
char GetLastSoftKeyChar(void);
int GetLastSoftKeyUnicode(void);
void ClearLastSoftKey(void);

It's still rather rudimentary for now, and there's an issue with converting jchar, which is an unsigned short, to char, which can be problematic.

But here's the code in action:

https://github.com/Bigfoot71/Raymob/assets/90587919/962b2ecc-bcc4-4661-961f-8d7bcecfb5a5

There's definitely room for improvement, so if you have any suggestions or feedback, please feel free to share them!

NerdyPuzzle commented 1 year ago

Great work! This is definitely a step forward from not being able to use the keyboard at all. I'd be happy to see improvements but even this is already very usable!

Bigfoot71 commented 1 year ago

It's done! We finally have a keyboard system that seems to be fully functional!

I've modified the previous functions, but more importantly, I've added a new function:

void SoftKeyboardEditText(char* text, unsigned int size)

This function allows you to directly provide it with a C string and its size, and when you manipulate the keyboard, the string will be automatically updated!

Here's a little demonstration:

https://github.com/Bigfoot71/Raymob/assets/90587919/fc7ac0a6-3155-4ac1-a42f-dc34457fa7fd

I hope this suits your needs. I think this issue can be closed now. If you have any suggestions or encounter any other issues, please don't hesitate to open a new issue or even a pull request!

vb8146649 commented 1 month ago

Can i use the IS_KEY_DOWN feature in mobile devices or is there another way to play the game using pc keyboard

Bigfoot71 commented 1 month ago

Can i use the IS_KEY_DOWN feature in mobile devices or is there another way to play the game using pc keyboard

@vb8146649 Technically, yes. If you have a physical keyboard connected to your Android device, raylib should be able to detect the state of the keys and return them to you using functions like IsKeyDown, IsKeyPressed, etc.

However, I haven’t personally tried this.

If you encounter any issues with this setup, consider reaching out on the raylib Discord or opening an issue on the raylib repository, as physical keyboards are supposed to be supported by raylib, even for those not using raymob.