@ -2,12 +2,13 @@
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
@ -18,6 +19,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-01-10: Inputs: calling new io.AddKeyEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-03-04: Initial version.
# include "imgui.h"
@ -30,11 +32,135 @@
# include <android/keycodes.h>
# include <android/log.h>
struct KeyEvent
{
ImGuiKey Key ;
bool Down ;
int NativeKeycode ;
int NativeScancode ;
KeyEvent ( ) : Key ( ImGuiKey_None ) , Down ( false ) , NativeKeycode ( - 1 ) , NativeScancode ( - 1 ) { }
} ;
// Android data
static double g_Time = 0.0 ;
static ANativeWindow * g_Window ;
static char g_LogTag [ ] = " ImGuiExample " ;
static std : : map < int32_t , std : : queue < int32_t > > g_KeyEventQueues ; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
static std : : map < ImGuiKey , std : : queue < KeyEvent > > g_KeyEventQueues ; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
static ImGuiKeyModFlags g_KeyModFlags = ImGuiKeyModFlags_None ;
static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey ( int32_t key_code )
{
switch ( key_code )
{
case AKEYCODE_TAB : return ImGuiKey_Tab ;
case AKEYCODE_DPAD_LEFT : return ImGuiKey_LeftArrow ;
case AKEYCODE_DPAD_RIGHT : return ImGuiKey_RightArrow ;
case AKEYCODE_DPAD_UP : return ImGuiKey_UpArrow ;
case AKEYCODE_DPAD_DOWN : return ImGuiKey_DownArrow ;
case AKEYCODE_PAGE_UP : return ImGuiKey_PageUp ;
case AKEYCODE_PAGE_DOWN : return ImGuiKey_PageDown ;
case AKEYCODE_MOVE_HOME : return ImGuiKey_Home ;
case AKEYCODE_MOVE_END : return ImGuiKey_End ;
case AKEYCODE_INSERT : return ImGuiKey_Insert ;
case AKEYCODE_FORWARD_DEL : return ImGuiKey_Delete ;
case AKEYCODE_DEL : return ImGuiKey_Backspace ;
case AKEYCODE_SPACE : return ImGuiKey_Space ;
case AKEYCODE_ENTER : return ImGuiKey_Enter ;
case AKEYCODE_ESCAPE : return ImGuiKey_Escape ;
case AKEYCODE_APOSTROPHE : return ImGuiKey_Apostrophe ;
case AKEYCODE_COMMA : return ImGuiKey_Comma ;
case AKEYCODE_MINUS : return ImGuiKey_Minus ;
case AKEYCODE_PERIOD : return ImGuiKey_Period ;
case AKEYCODE_SLASH : return ImGuiKey_Slash ;
case AKEYCODE_SEMICOLON : return ImGuiKey_Semicolon ;
case AKEYCODE_EQUALS : return ImGuiKey_Equal ;
case AKEYCODE_LEFT_BRACKET : return ImGuiKey_LeftBracket ;
case AKEYCODE_BACKSLASH : return ImGuiKey_Backslash ;
case AKEYCODE_RIGHT_BRACKET : return ImGuiKey_RightBracket ;
case AKEYCODE_GRAVE : return ImGuiKey_GraveAccent ;
case AKEYCODE_CAPS_LOCK : return ImGuiKey_CapsLock ;
case AKEYCODE_SCROLL_LOCK : return ImGuiKey_ScrollLock ;
case AKEYCODE_NUM_LOCK : return ImGuiKey_NumLock ;
case AKEYCODE_SYSRQ : return ImGuiKey_PrintScreen ;
case AKEYCODE_BREAK : return ImGuiKey_Pause ;
case AKEYCODE_NUMPAD_0 : return ImGuiKey_Keypad0 ;
case AKEYCODE_NUMPAD_1 : return ImGuiKey_Keypad1 ;
case AKEYCODE_NUMPAD_2 : return ImGuiKey_Keypad2 ;
case AKEYCODE_NUMPAD_3 : return ImGuiKey_Keypad3 ;
case AKEYCODE_NUMPAD_4 : return ImGuiKey_Keypad4 ;
case AKEYCODE_NUMPAD_5 : return ImGuiKey_Keypad5 ;
case AKEYCODE_NUMPAD_6 : return ImGuiKey_Keypad6 ;
case AKEYCODE_NUMPAD_7 : return ImGuiKey_Keypad7 ;
case AKEYCODE_NUMPAD_8 : return ImGuiKey_Keypad8 ;
case AKEYCODE_NUMPAD_9 : return ImGuiKey_Keypad9 ;
case AKEYCODE_NUMPAD_DOT : return ImGuiKey_KeypadDecimal ;
case AKEYCODE_NUMPAD_DIVIDE : return ImGuiKey_KeypadDivide ;
case AKEYCODE_NUMPAD_MULTIPLY : return ImGuiKey_KeypadMultiply ;
case AKEYCODE_NUMPAD_SUBTRACT : return ImGuiKey_KeypadSubtract ;
case AKEYCODE_NUMPAD_ADD : return ImGuiKey_KeypadAdd ;
case AKEYCODE_NUMPAD_ENTER : return ImGuiKey_KeypadEnter ;
case AKEYCODE_NUMPAD_EQUALS : return ImGuiKey_KeypadEqual ;
case AKEYCODE_SHIFT_LEFT : return ImGuiKey_LeftShift ;
case AKEYCODE_CTRL_LEFT : return ImGuiKey_LeftControl ;
case AKEYCODE_ALT_LEFT : return ImGuiKey_LeftAlt ;
case AKEYCODE_META_LEFT : return ImGuiKey_LeftSuper ;
case AKEYCODE_SHIFT_RIGHT : return ImGuiKey_RightShift ;
case AKEYCODE_CTRL_RIGHT : return ImGuiKey_RightControl ;
case AKEYCODE_ALT_RIGHT : return ImGuiKey_RightAlt ;
case AKEYCODE_META_RIGHT : return ImGuiKey_RightSuper ;
case AKEYCODE_MENU : return ImGuiKey_Menu ;
case AKEYCODE_0 : return ImGuiKey_0 ;
case AKEYCODE_1 : return ImGuiKey_1 ;
case AKEYCODE_2 : return ImGuiKey_2 ;
case AKEYCODE_3 : return ImGuiKey_3 ;
case AKEYCODE_4 : return ImGuiKey_4 ;
case AKEYCODE_5 : return ImGuiKey_5 ;
case AKEYCODE_6 : return ImGuiKey_6 ;
case AKEYCODE_7 : return ImGuiKey_7 ;
case AKEYCODE_8 : return ImGuiKey_8 ;
case AKEYCODE_9 : return ImGuiKey_9 ;
case AKEYCODE_A : return ImGuiKey_A ;
case AKEYCODE_B : return ImGuiKey_B ;
case AKEYCODE_C : return ImGuiKey_C ;
case AKEYCODE_D : return ImGuiKey_D ;
case AKEYCODE_E : return ImGuiKey_E ;
case AKEYCODE_F : return ImGuiKey_F ;
case AKEYCODE_G : return ImGuiKey_G ;
case AKEYCODE_H : return ImGuiKey_H ;
case AKEYCODE_I : return ImGuiKey_I ;
case AKEYCODE_J : return ImGuiKey_J ;
case AKEYCODE_K : return ImGuiKey_K ;
case AKEYCODE_L : return ImGuiKey_L ;
case AKEYCODE_M : return ImGuiKey_M ;
case AKEYCODE_N : return ImGuiKey_N ;
case AKEYCODE_O : return ImGuiKey_O ;
case AKEYCODE_P : return ImGuiKey_P ;
case AKEYCODE_Q : return ImGuiKey_Q ;
case AKEYCODE_R : return ImGuiKey_R ;
case AKEYCODE_S : return ImGuiKey_S ;
case AKEYCODE_T : return ImGuiKey_T ;
case AKEYCODE_U : return ImGuiKey_U ;
case AKEYCODE_V : return ImGuiKey_V ;
case AKEYCODE_W : return ImGuiKey_W ;
case AKEYCODE_X : return ImGuiKey_X ;
case AKEYCODE_Y : return ImGuiKey_Y ;
case AKEYCODE_Z : return ImGuiKey_Z ;
case AKEYCODE_F1 : return ImGuiKey_F1 ;
case AKEYCODE_F2 : return ImGuiKey_F2 ;
case AKEYCODE_F3 : return ImGuiKey_F3 ;
case AKEYCODE_F4 : return ImGuiKey_F4 ;
case AKEYCODE_F5 : return ImGuiKey_F5 ;
case AKEYCODE_F6 : return ImGuiKey_F6 ;
case AKEYCODE_F7 : return ImGuiKey_F7 ;
case AKEYCODE_F8 : return ImGuiKey_F8 ;
case AKEYCODE_F9 : return ImGuiKey_F9 ;
case AKEYCODE_F10 : return ImGuiKey_F10 ;
case AKEYCODE_F11 : return ImGuiKey_F11 ;
case AKEYCODE_F12 : return ImGuiKey_F12 ;
default : return ImGuiKey_None ;
}
}
int32_t ImGui_ImplAndroid_HandleInputEvent ( AInputEvent * input_event )
{
@ -45,12 +171,19 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
case AINPUT_EVENT_TYPE_KEY :
{
int32_t event_key_code = AKeyEvent_getKeyCode ( input_event ) ;
int32_t event_scan_code = AKeyEvent_getScanCode ( input_event ) ;
int32_t event_action = AKeyEvent_getAction ( input_event ) ;
int32_t event_meta_state = AKeyEvent_getMetaState ( input_event ) ;
io . KeyCtrl = ( ( event_meta_state & AMETA_CTRL_ON ) ! = 0 ) ;
io . KeyShift = ( ( event_meta_state & AMETA_SHIFT_ON ) ! = 0 ) ;
io . KeyAlt = ( ( event_meta_state & AMETA_ALT_ON ) ! = 0 ) ;
g_KeyModFlags = ImGuiKeyModFlags_None ;
if ( ( event_meta_state & AMETA_CTRL_ON ) ! = 0 )
g_KeyModFlags | = ImGuiKeyModFlags_Ctrl ;
if ( ( event_meta_state & AMETA_SHIFT_ON ) ! = 0 )
g_KeyModFlags | = ImGuiKeyModFlags_Shift ;
if ( ( event_meta_state & AMETA_ALT_ON ) ! = 0 )
g_KeyModFlags | = ImGuiKeyModFlags_Alt ;
if ( ( event_meta_state & AMETA_META_ON ) ! = 0 )
g_KeyModFlags | = ImGuiKeyModFlags_Super ;
switch ( event_action )
{
@ -59,8 +192,21 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
case AKEY_EVENT_ACTION_DOWN :
case AKEY_EVENT_ACTION_UP :
g_KeyEventQueues [ event_key_code ] . push ( event_action ) ;
{
ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey ( event_key_code ) ;
if ( key ! = ImGuiKey_None & & ( event_action = = AKEY_EVENT_ACTION_DOWN | | event_action = = AKEY_EVENT_ACTION_UP ) )
{
KeyEvent io_event ;
io_event . Key = key ;
io_event . Down = event_action = = AKEY_EVENT_ACTION_DOWN ;
io_event . NativeKeycode = event_key_code ;
io_event . NativeScancode = event_scan_code ;
g_KeyEventQueues [ key ] . push ( io_event ) ;
}
break ;
}
default :
break ;
}
@ -123,30 +269,6 @@ bool ImGui_ImplAndroid_Init(ANativeWindow* window)
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . BackendPlatformName = " imgui_impl_android " ;
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io . KeyMap [ ImGuiKey_Tab ] = AKEYCODE_TAB ;
io . KeyMap [ ImGuiKey_LeftArrow ] = AKEYCODE_DPAD_LEFT ; // also covers physical keyboard arrow key
io . KeyMap [ ImGuiKey_RightArrow ] = AKEYCODE_DPAD_RIGHT ; // also covers physical keyboard arrow key
io . KeyMap [ ImGuiKey_UpArrow ] = AKEYCODE_DPAD_UP ; // also covers physical keyboard arrow key
io . KeyMap [ ImGuiKey_DownArrow ] = AKEYCODE_DPAD_DOWN ; // also covers physical keyboard arrow key
io . KeyMap [ ImGuiKey_PageUp ] = AKEYCODE_PAGE_UP ;
io . KeyMap [ ImGuiKey_PageDown ] = AKEYCODE_PAGE_DOWN ;
io . KeyMap [ ImGuiKey_Home ] = AKEYCODE_MOVE_HOME ;
io . KeyMap [ ImGuiKey_End ] = AKEYCODE_MOVE_END ;
io . KeyMap [ ImGuiKey_Insert ] = AKEYCODE_INSERT ;
io . KeyMap [ ImGuiKey_Delete ] = AKEYCODE_FORWARD_DEL ;
io . KeyMap [ ImGuiKey_Backspace ] = AKEYCODE_DEL ;
io . KeyMap [ ImGuiKey_Space ] = AKEYCODE_SPACE ;
io . KeyMap [ ImGuiKey_Enter ] = AKEYCODE_ENTER ;
io . KeyMap [ ImGuiKey_Escape ] = AKEYCODE_ESCAPE ;
io . KeyMap [ ImGuiKey_KeypadEnter ] = AKEYCODE_NUMPAD_ENTER ;
io . KeyMap [ ImGuiKey_A ] = AKEYCODE_A ;
io . KeyMap [ ImGuiKey_C ] = AKEYCODE_C ;
io . KeyMap [ ImGuiKey_V ] = AKEYCODE_V ;
io . KeyMap [ ImGuiKey_X ] = AKEYCODE_X ;
io . KeyMap [ ImGuiKey_Y ] = AKEYCODE_Y ;
io . KeyMap [ ImGuiKey_Z ] = AKEYCODE_Z ;
return true ;
}
@ -164,10 +286,18 @@ void ImGui_ImplAndroid_NewFrame()
{
if ( key_queue . second . empty ( ) )
continue ;
io . KeysDown [ key_queue . first ] = ( key_queue . second . front ( ) = = AKEY_EVENT_ACTION_DOWN ) ;
auto & key_event = key_queue . second . front ( ) ;
io . AddKeyEvent ( key_event . Key , key_event . Down ) ;
io . SetKeyEventNativeData ( key_event . Key , key_event . NativeKeycode , key_event . NativeScancode ) ; // To support legacy indexing (<1.87 user code)
key_queue . second . pop ( ) ;
}
io . KeyCtrl = ( ( g_KeyModFlags & ImGuiKeyModFlags_Ctrl ) ! = 0 ) ;
io . KeyShift = ( ( g_KeyModFlags & ImGuiKeyModFlags_Shift ) ! = 0 ) ;
io . KeyAlt = ( ( g_KeyModFlags & ImGuiKeyModFlags_Alt ) ! = 0 ) ;
io . KeySuper = ( ( g_KeyModFlags & ImGuiKeyModFlags_Super ) ! = 0 ) ;
// Setup display size (every frame to accommodate for window resizing)
int32_t window_width = ANativeWindow_getWidth ( g_Window ) ;
int32_t window_height = ANativeWindow_getHeight ( g_Window ) ;