772 lines
25 KiB
C++
772 lines
25 KiB
C++
// Filename: androidGraphicsWindow.cxx
|
|
// Created by: rdb (11Jan13)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "androidGraphicsWindow.h"
|
|
#include "androidGraphicsStateGuardian.h"
|
|
#include "config_androiddisplay.h"
|
|
#include "androidGraphicsPipe.h"
|
|
|
|
#include "graphicsPipe.h"
|
|
#include "keyboardButton.h"
|
|
#include "mouseButton.h"
|
|
#include "clockObject.h"
|
|
#include "pStatTimer.h"
|
|
#include "textEncoder.h"
|
|
#include "throw_event.h"
|
|
#include "nativeWindowHandle.h"
|
|
|
|
#include "android_native_app_glue.h"
|
|
#include <android/window.h>
|
|
#include <android/log.h>
|
|
|
|
extern struct android_app* panda_android_app;
|
|
|
|
TypeHandle AndroidGraphicsWindow::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
AndroidGraphicsWindow::
|
|
AndroidGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
|
|
const string &name,
|
|
const FrameBufferProperties &fb_prop,
|
|
const WindowProperties &win_prop,
|
|
int flags,
|
|
GraphicsStateGuardian *gsg,
|
|
GraphicsOutput *host) :
|
|
GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
|
|
{
|
|
AndroidGraphicsPipe *android_pipe;
|
|
DCAST_INTO_V(android_pipe, _pipe);
|
|
|
|
_egl_display = android_pipe->_egl_display;
|
|
_egl_surface = 0;
|
|
|
|
_app = panda_android_app;
|
|
|
|
GraphicsWindowInputDevice device =
|
|
GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
|
|
add_input_device(device);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
AndroidGraphicsWindow::
|
|
~AndroidGraphicsWindow() {
|
|
destroy_surface();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::begin_frame
|
|
// Access: Public, Virtual
|
|
// Description: This function will be called within the draw thread
|
|
// before beginning rendering for a given frame. It
|
|
// should do whatever setup is required, and return true
|
|
// if the frame should be rendered, or false if it
|
|
// should be skipped.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool AndroidGraphicsWindow::
|
|
begin_frame(FrameMode mode, Thread *current_thread) {
|
|
PStatTimer timer(_make_current_pcollector, current_thread);
|
|
|
|
begin_frame_spam(mode);
|
|
if (_gsg == (GraphicsStateGuardian *)NULL) {
|
|
return false;
|
|
}
|
|
|
|
//XXX not open yet.
|
|
if (_egl_surface == EGL_NO_SURFACE) {
|
|
return false;
|
|
}
|
|
|
|
AndroidGraphicsStateGuardian *androidgsg;
|
|
DCAST_INTO_R(androidgsg, _gsg, false);
|
|
{
|
|
if (eglGetCurrentDisplay() == _egl_display &&
|
|
eglGetCurrentSurface(EGL_READ) == _egl_surface &&
|
|
eglGetCurrentSurface(EGL_DRAW) == _egl_surface &&
|
|
eglGetCurrentContext() == androidgsg->_context) {
|
|
// No need to make the context current again. Short-circuit
|
|
// this possibly-expensive call.
|
|
} else {
|
|
// Need to set the context.
|
|
if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
|
|
androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
|
|
<< get_egl_error_string(eglGetError()) << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now that we have made the context current to a window, we can
|
|
// reset the GSG state if this is the first time it has been used.
|
|
// (We can't just call reset() when we construct the GSG, because
|
|
// reset() requires having a current context.)
|
|
androidgsg->reset_if_new();
|
|
|
|
if (mode == FM_render) {
|
|
// begin_render_texture();
|
|
clear_cube_map_selection();
|
|
}
|
|
|
|
_gsg->set_current_properties(&get_fb_properties());
|
|
return _gsg->begin_frame(current_thread);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::end_frame
|
|
// Access: Public, Virtual
|
|
// Description: This function will be called within the draw thread
|
|
// after rendering is completed for a given frame. It
|
|
// should do whatever finalization is required.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
end_frame(FrameMode mode, Thread *current_thread) {
|
|
end_frame_spam(mode);
|
|
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
|
|
|
|
if (mode == FM_render) {
|
|
// end_render_texture();
|
|
copy_to_textures();
|
|
}
|
|
|
|
_gsg->end_frame(current_thread);
|
|
|
|
if (mode == FM_render) {
|
|
trigger_flip();
|
|
clear_cube_map_selection();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::end_flip
|
|
// Access: Public, Virtual
|
|
// Description: This function will be called within the draw thread
|
|
// after begin_flip() has been called on all windows, to
|
|
// finish the exchange of the front and back buffers.
|
|
//
|
|
// This should cause the window to wait for the flip, if
|
|
// necessary.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
end_flip() {
|
|
if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) {
|
|
|
|
// It doesn't appear to be necessary to ensure the graphics
|
|
// context is current before flipping the windows, and insisting
|
|
// on doing so can be a significant performance hit.
|
|
|
|
//make_current();
|
|
|
|
if (_egl_surface != EGL_NO_SURFACE) {
|
|
eglSwapBuffers(_egl_display, _egl_surface);
|
|
}
|
|
}
|
|
GraphicsWindow::end_flip();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::process_events
|
|
// Access: Public, Virtual
|
|
// Description: Do whatever processing is necessary to ensure that
|
|
// the window responds to user events. Also, honor any
|
|
// requests recently made via request_properties()
|
|
//
|
|
// This function is called only within the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
process_events() {
|
|
GraphicsWindow::process_events();
|
|
|
|
// Read all pending events.
|
|
int looper_id;
|
|
int events;
|
|
struct android_poll_source* source;
|
|
|
|
// Loop until all events are read.
|
|
while ((looper_id = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) {
|
|
// Process this event.
|
|
if (source != NULL) {
|
|
source->process(_app, source);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::set_properties_now
|
|
// Access: Public, Virtual
|
|
// Description: Applies the requested set of properties to the
|
|
// window, if possible, for instance to request a change
|
|
// in size or minimization status.
|
|
//
|
|
// The window properties are applied immediately, rather
|
|
// than waiting until the next frame. This implies that
|
|
// this method may *only* be called from within the
|
|
// window thread.
|
|
//
|
|
// The return value is true if the properties are set,
|
|
// false if they are ignored. This is mainly useful for
|
|
// derived classes to implement extensions to this
|
|
// function.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
set_properties_now(WindowProperties &properties) {
|
|
if (_pipe == (GraphicsPipe *)NULL) {
|
|
// If the pipe is null, we're probably closing down.
|
|
GraphicsWindow::set_properties_now(properties);
|
|
return;
|
|
}
|
|
|
|
GraphicsWindow::set_properties_now(properties);
|
|
if (!properties.is_any_specified()) {
|
|
// The base class has already handled this case.
|
|
return;
|
|
}
|
|
|
|
// There's not really much we can change on Android.
|
|
if (properties.has_fullscreen()) {
|
|
uint32_t add_flags = 0;
|
|
uint32_t del_flags = 0;
|
|
if (_properties.get_fullscreen()) {
|
|
add_flags |= AWINDOW_FLAG_FULLSCREEN;
|
|
} else {
|
|
del_flags |= AWINDOW_FLAG_FULLSCREEN;
|
|
}
|
|
ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
|
|
|
|
_properties.set_fullscreen(properties.get_fullscreen());
|
|
properties.clear_fullscreen();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::close_window
|
|
// Access: Protected, Virtual
|
|
// Description: Closes the window right now. Called from the window
|
|
// thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
close_window() {
|
|
destroy_surface();
|
|
|
|
if (_gsg != (GraphicsStateGuardian *)NULL) {
|
|
_gsg.clear();
|
|
}
|
|
|
|
GraphicsWindow::close_window();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::open_window
|
|
// Access: Protected, Virtual
|
|
// Description: Opens the window right now. Called from the window
|
|
// thread. Returns true if the window is successfully
|
|
// opened, or false if there was a problem.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool AndroidGraphicsWindow::
|
|
open_window() {
|
|
// GSG Creation/Initialization
|
|
AndroidGraphicsStateGuardian *androidgsg;
|
|
if (_gsg == 0) {
|
|
// There is no old gsg. Create a new one.
|
|
androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, NULL);
|
|
androidgsg->choose_pixel_format(_fb_properties, false, false);
|
|
_gsg = androidgsg;
|
|
} else {
|
|
// If the old gsg has the wrong pixel format, create a
|
|
// new one that shares with the old gsg.
|
|
DCAST_INTO_R(androidgsg, _gsg, false);
|
|
if (!androidgsg->get_fb_properties().subsumes(_fb_properties)) {
|
|
androidgsg = new AndroidGraphicsStateGuardian(_engine, _pipe, androidgsg);
|
|
androidgsg->choose_pixel_format(_fb_properties, false, false);
|
|
_gsg = androidgsg;
|
|
}
|
|
}
|
|
|
|
// Register the callbacks
|
|
assert(_app != NULL);
|
|
_app->userData = this;
|
|
_app->onAppCmd = handle_command;
|
|
_app->onInputEvent = handle_input_event;
|
|
|
|
// Wait until Android has opened the window.
|
|
while (_app->window == NULL) {
|
|
process_events();
|
|
}
|
|
|
|
// create_surface should have been called by now.
|
|
if (_egl_surface == EGL_NO_SURFACE) {
|
|
return false;
|
|
}
|
|
|
|
// Set some other properties.
|
|
_properties.set_origin(0, 0);
|
|
_properties.set_cursor_hidden(true);
|
|
_properties.set_undecorated(true);
|
|
|
|
if (!androidgsg->get_fb_properties().verify_hardware_software
|
|
(_fb_properties, androidgsg->get_gl_renderer())) {
|
|
close_window();
|
|
return false;
|
|
}
|
|
|
|
//_fb_properties = androidgsg->get_fb_properties();
|
|
|
|
androiddisplay_cat.error() << "open_window done\n";
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::destroy_surface
|
|
// Access: Protected, Virtual
|
|
// Description: Terminates the EGL surface.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
destroy_surface() {
|
|
if (_egl_surface != EGL_NO_SURFACE) {
|
|
if (!eglDestroySurface(_egl_display, _egl_surface)) {
|
|
androiddisplay_cat.error() << "Failed to destroy surface: "
|
|
<< get_egl_error_string(eglGetError()) << "\n";
|
|
}
|
|
_egl_surface = EGL_NO_SURFACE;
|
|
}
|
|
|
|
// Destroy the current context.
|
|
if (_gsg != (GraphicsStateGuardian *)NULL) {
|
|
AndroidGraphicsStateGuardian *androidgsg;
|
|
DCAST_INTO_V(androidgsg, _gsg);
|
|
androidgsg->destroy_context();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::create_surface
|
|
// Access: Protected, Virtual
|
|
// Description: Creates the EGL surface.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool AndroidGraphicsWindow::
|
|
create_surface() {
|
|
AndroidGraphicsStateGuardian *androidgsg;
|
|
DCAST_INTO_R(androidgsg, _gsg, false);
|
|
|
|
// Reconfigure the window buffers to match that of our framebuffer config.
|
|
ANativeWindow_setBuffersGeometry(_app->window, 0, 0, androidgsg->_format);
|
|
|
|
// Set any window flags
|
|
uint32_t add_flags = 0;
|
|
uint32_t del_flags = 0;
|
|
if (_properties.get_fullscreen()) {
|
|
add_flags |= AWINDOW_FLAG_FULLSCREEN;
|
|
} else {
|
|
del_flags |= AWINDOW_FLAG_FULLSCREEN;
|
|
}
|
|
ANativeActivity_setWindowFlags(_app->activity, add_flags, del_flags);
|
|
|
|
// Create the EGL surface.
|
|
_egl_surface = eglCreateWindowSurface(_egl_display, androidgsg->_fbconfig, _app->window, NULL);
|
|
if (eglGetError() != EGL_SUCCESS) {
|
|
androiddisplay_cat.error()
|
|
<< "Failed to create window surface.\n";
|
|
return false;
|
|
}
|
|
|
|
// Create a context.
|
|
if (androidgsg->_context == EGL_NO_CONTEXT) {
|
|
androiddisplay_cat.error() << "creating context\n";
|
|
if (!androidgsg->create_context()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Switch to our newly created context.
|
|
if (!eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, androidgsg->_context)) {
|
|
androiddisplay_cat.error() << "Failed to call eglMakeCurrent: "
|
|
<< get_egl_error_string(eglGetError()) << "\n";
|
|
}
|
|
|
|
// Query the size of the surface.
|
|
//EGLint width, height;
|
|
//eglQuerySurface(_egl_display, _egl_surface, EGL_WIDTH, &width);
|
|
//eglQuerySurface(_egl_display, _egl_surface, EGL_HEIGHT, &height);
|
|
|
|
androidgsg->reset_if_new();
|
|
if (!androidgsg->is_valid()) {
|
|
close_window();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::handle_command
|
|
// Access: Private, Static
|
|
// Description: Android app sends a command from the main thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
handle_command(struct android_app *app, int32_t command) {
|
|
AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
|
|
window->ns_handle_command(command);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::ns_handle_command
|
|
// Access: Private
|
|
// Description: Android app sends a command from the main thread.
|
|
////////////////////////////////////////////////////////////////////
|
|
void AndroidGraphicsWindow::
|
|
ns_handle_command(int32_t command) {
|
|
WindowProperties properties;
|
|
|
|
switch (command) {
|
|
case APP_CMD_SAVE_STATE:
|
|
// The system has asked us to save our current state. Do so.
|
|
//engine->app->savedState = malloc(sizeof(struct saved_state));
|
|
//*((struct saved_state*)engine->app->savedState) = engine->state;
|
|
//engine->app->savedStateSize = sizeof(struct saved_state);
|
|
break;
|
|
case APP_CMD_INIT_WINDOW:
|
|
// The window is being shown, get it ready.
|
|
if (_app->window != NULL) {
|
|
create_surface();
|
|
properties.set_minimized(false);
|
|
system_changed_properties(properties);
|
|
}
|
|
break;
|
|
case APP_CMD_TERM_WINDOW:
|
|
destroy_surface();
|
|
properties.set_minimized(true);
|
|
system_changed_properties(properties);
|
|
break;
|
|
case APP_CMD_WINDOW_RESIZED:
|
|
break;
|
|
case APP_CMD_WINDOW_REDRAW_NEEDED:
|
|
break;
|
|
case APP_CMD_CONTENT_RECT_CHANGED:
|
|
properties.set_origin(_app->contentRect.left, _app->contentRect.top);
|
|
properties.set_size(_app->contentRect.right - _app->contentRect.left,
|
|
_app->contentRect.bottom - _app->contentRect.top);
|
|
system_changed_properties(properties);
|
|
break;
|
|
case APP_CMD_GAINED_FOCUS:
|
|
properties.set_foreground(true);
|
|
system_changed_properties(properties);
|
|
break;
|
|
case APP_CMD_LOST_FOCUS:
|
|
properties.set_foreground(false);
|
|
system_changed_properties(properties);
|
|
break;
|
|
case APP_CMD_DESTROY:
|
|
close_window();
|
|
properties.set_open(false);
|
|
system_changed_properties(properties);
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::handle_input_event
|
|
// Access: Private, Static
|
|
// Description: Processes an input event. Returns 1 if the event
|
|
// was handled, 0 otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
int32_t AndroidGraphicsWindow::
|
|
handle_input_event(struct android_app* app, AInputEvent *event) {
|
|
AndroidGraphicsWindow* window = (AndroidGraphicsWindow*) app->userData;
|
|
|
|
int32_t event_type = AInputEvent_getType(event);
|
|
switch (event_type) {
|
|
case AINPUT_EVENT_TYPE_KEY:
|
|
return window->handle_key_event(event);
|
|
case AINPUT_EVENT_TYPE_MOTION:
|
|
return window->handle_motion_event(event);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::handle_keystroke
|
|
// Access: Private
|
|
// Description: Processes a key event.
|
|
////////////////////////////////////////////////////////////////////
|
|
int32_t AndroidGraphicsWindow::
|
|
handle_key_event(const AInputEvent *event) {
|
|
/*
|
|
int32_t meta = AKeyEvent_getMetaState(event);
|
|
if (meta | AMETA_ALT_ON) {
|
|
_input_devices[0].button_down(KeyboardButton.alt());
|
|
}
|
|
if (meta | AMETA_ALT_LEFT_ON) {
|
|
_input_devices[0].button_down(KeyboardButton.lalt());
|
|
}
|
|
if (meta | AMETA_ALT_RIGHT_ON) {
|
|
_input_devices[0].button_down(KeyboardButton.ralt());
|
|
}
|
|
if (meta | AMETA_SHIFT_ON) {
|
|
_input_devices[0].button_down(KeyboardButton.shift());
|
|
}
|
|
if (meta | AMETA_SHIFT_LEFT_ON) {
|
|
_input_devices[0].button_down(KeyboardButton.lshift());
|
|
}
|
|
if (meta | AMETA_SHIFT_RIGHT_ON) {
|
|
_input_devices[0].button_down(KeyboardButton.rshift());
|
|
}*/
|
|
|
|
int32_t keycode = AKeyEvent_getKeyCode(event);
|
|
ButtonHandle button = map_button(keycode);
|
|
|
|
if (button == ButtonHandle::none()) {
|
|
androiddisplay_cat.warning()
|
|
<< "Unknown keycode: " << keycode << "\n";
|
|
return 0;
|
|
}
|
|
|
|
// Is it an up or down event?
|
|
int32_t action = AKeyEvent_getAction(event);
|
|
if (action == AKEY_EVENT_ACTION_DOWN) {
|
|
_input_devices[0].button_down(button);
|
|
} else if (action == AKEY_EVENT_ACTION_UP) {
|
|
_input_devices[0].button_up(button);
|
|
}
|
|
//TODO getRepeatCount, ACTION_MULTIPLE
|
|
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::handle_motion_event
|
|
// Access: Private
|
|
// Description: Processes a motion event.
|
|
////////////////////////////////////////////////////////////////////
|
|
int32_t AndroidGraphicsWindow::
|
|
handle_motion_event(const AInputEvent *event) {
|
|
int32_t action = AMotionEvent_getAction(event);
|
|
action &= AMOTION_EVENT_ACTION_MASK;
|
|
|
|
if (action == AMOTION_EVENT_ACTION_DOWN) {
|
|
_input_devices[0].button_down(MouseButton::one());
|
|
} else if (action == AMOTION_EVENT_ACTION_UP) {
|
|
_input_devices[0].button_up(MouseButton::one());
|
|
}
|
|
|
|
float x = AMotionEvent_getX(event, 0) - _app->contentRect.left;
|
|
float y = AMotionEvent_getY(event, 0) - _app->contentRect.top;
|
|
|
|
_input_devices[0].set_pointer_in_window(x, y);
|
|
|
|
return 1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AndroidGraphicsWindow::map_button
|
|
// Access: Private
|
|
// Description: Given an Android keycode, returns an appropriate
|
|
// ButtonHandle object, or ButtonHandle::none() if
|
|
// a matching ButtonHandle does not exist.
|
|
////////////////////////////////////////////////////////////////////
|
|
ButtonHandle AndroidGraphicsWindow::
|
|
map_button(int32_t keycode) {
|
|
switch (keycode) {
|
|
case AKEYCODE_SOFT_LEFT:
|
|
case AKEYCODE_SOFT_RIGHT:
|
|
case AKEYCODE_HOME:
|
|
case AKEYCODE_BACK:
|
|
case AKEYCODE_CALL:
|
|
case AKEYCODE_ENDCALL:
|
|
break;
|
|
case AKEYCODE_0:
|
|
return KeyboardButton::ascii_key('0');
|
|
case AKEYCODE_1:
|
|
return KeyboardButton::ascii_key('1');
|
|
case AKEYCODE_2:
|
|
return KeyboardButton::ascii_key('2');
|
|
case AKEYCODE_3:
|
|
return KeyboardButton::ascii_key('3');
|
|
case AKEYCODE_4:
|
|
return KeyboardButton::ascii_key('4');
|
|
case AKEYCODE_5:
|
|
return KeyboardButton::ascii_key('5');
|
|
case AKEYCODE_6:
|
|
return KeyboardButton::ascii_key('6');
|
|
case AKEYCODE_7:
|
|
return KeyboardButton::ascii_key('7');
|
|
case AKEYCODE_8:
|
|
return KeyboardButton::ascii_key('8');
|
|
case AKEYCODE_9:
|
|
return KeyboardButton::ascii_key('9');
|
|
case AKEYCODE_STAR:
|
|
return KeyboardButton::ascii_key('*');
|
|
case AKEYCODE_POUND:
|
|
return KeyboardButton::ascii_key('#');
|
|
case AKEYCODE_DPAD_UP:
|
|
return KeyboardButton::up();
|
|
case AKEYCODE_DPAD_DOWN:
|
|
return KeyboardButton::down();
|
|
case AKEYCODE_DPAD_LEFT:
|
|
return KeyboardButton::left();
|
|
case AKEYCODE_DPAD_RIGHT:
|
|
return KeyboardButton::right();
|
|
case AKEYCODE_DPAD_CENTER:
|
|
case AKEYCODE_VOLUME_UP:
|
|
case AKEYCODE_VOLUME_DOWN:
|
|
case AKEYCODE_POWER:
|
|
case AKEYCODE_CAMERA:
|
|
case AKEYCODE_CLEAR:
|
|
break;
|
|
case AKEYCODE_A:
|
|
return KeyboardButton::ascii_key('a');
|
|
case AKEYCODE_B:
|
|
return KeyboardButton::ascii_key('b');
|
|
case AKEYCODE_C:
|
|
return KeyboardButton::ascii_key('c');
|
|
case AKEYCODE_D:
|
|
return KeyboardButton::ascii_key('d');
|
|
case AKEYCODE_E:
|
|
return KeyboardButton::ascii_key('e');
|
|
case AKEYCODE_F:
|
|
return KeyboardButton::ascii_key('f');
|
|
case AKEYCODE_G:
|
|
return KeyboardButton::ascii_key('g');
|
|
case AKEYCODE_H:
|
|
return KeyboardButton::ascii_key('h');
|
|
case AKEYCODE_I:
|
|
return KeyboardButton::ascii_key('i');
|
|
case AKEYCODE_J:
|
|
return KeyboardButton::ascii_key('j');
|
|
case AKEYCODE_K:
|
|
return KeyboardButton::ascii_key('k');
|
|
case AKEYCODE_L:
|
|
return KeyboardButton::ascii_key('l');
|
|
case AKEYCODE_M:
|
|
return KeyboardButton::ascii_key('m');
|
|
case AKEYCODE_N:
|
|
return KeyboardButton::ascii_key('n');
|
|
case AKEYCODE_O:
|
|
return KeyboardButton::ascii_key('o');
|
|
case AKEYCODE_P:
|
|
return KeyboardButton::ascii_key('p');
|
|
case AKEYCODE_Q:
|
|
return KeyboardButton::ascii_key('q');
|
|
case AKEYCODE_R:
|
|
return KeyboardButton::ascii_key('r');
|
|
case AKEYCODE_S:
|
|
return KeyboardButton::ascii_key('s');
|
|
case AKEYCODE_T:
|
|
return KeyboardButton::ascii_key('t');
|
|
case AKEYCODE_U:
|
|
return KeyboardButton::ascii_key('u');
|
|
case AKEYCODE_V:
|
|
return KeyboardButton::ascii_key('v');
|
|
case AKEYCODE_W:
|
|
return KeyboardButton::ascii_key('w');
|
|
case AKEYCODE_X:
|
|
return KeyboardButton::ascii_key('x');
|
|
case AKEYCODE_Y:
|
|
return KeyboardButton::ascii_key('y');
|
|
case AKEYCODE_Z:
|
|
return KeyboardButton::ascii_key('z');
|
|
case AKEYCODE_COMMA:
|
|
return KeyboardButton::ascii_key(',');
|
|
case AKEYCODE_PERIOD:
|
|
return KeyboardButton::ascii_key('.');
|
|
case AKEYCODE_ALT_LEFT:
|
|
return KeyboardButton::lalt();
|
|
case AKEYCODE_ALT_RIGHT:
|
|
return KeyboardButton::ralt();
|
|
case AKEYCODE_SHIFT_LEFT:
|
|
return KeyboardButton::lshift();
|
|
case AKEYCODE_SHIFT_RIGHT:
|
|
return KeyboardButton::rshift();
|
|
case AKEYCODE_TAB:
|
|
return KeyboardButton::tab();
|
|
case AKEYCODE_SPACE:
|
|
return KeyboardButton::space();
|
|
case AKEYCODE_SYM:
|
|
case AKEYCODE_EXPLORER:
|
|
case AKEYCODE_ENVELOPE:
|
|
break;
|
|
case AKEYCODE_ENTER:
|
|
return KeyboardButton::enter();
|
|
case AKEYCODE_DEL:
|
|
return KeyboardButton::del();
|
|
case AKEYCODE_GRAVE:
|
|
return KeyboardButton::ascii_key('`');
|
|
case AKEYCODE_MINUS:
|
|
return KeyboardButton::ascii_key('-');
|
|
case AKEYCODE_EQUALS:
|
|
return KeyboardButton::ascii_key('=');
|
|
case AKEYCODE_LEFT_BRACKET:
|
|
return KeyboardButton::ascii_key('[');
|
|
case AKEYCODE_RIGHT_BRACKET:
|
|
return KeyboardButton::ascii_key(']');
|
|
case AKEYCODE_BACKSLASH:
|
|
return KeyboardButton::ascii_key('\\');
|
|
case AKEYCODE_SEMICOLON:
|
|
return KeyboardButton::ascii_key(';');
|
|
case AKEYCODE_APOSTROPHE:
|
|
return KeyboardButton::ascii_key('\'');
|
|
case AKEYCODE_SLASH:
|
|
return KeyboardButton::ascii_key('/');
|
|
case AKEYCODE_AT:
|
|
return KeyboardButton::ascii_key('@');
|
|
case AKEYCODE_NUM:
|
|
case AKEYCODE_HEADSETHOOK:
|
|
case AKEYCODE_FOCUS:
|
|
break;
|
|
case AKEYCODE_PLUS:
|
|
return KeyboardButton::ascii_key('+');
|
|
case AKEYCODE_MENU:
|
|
case AKEYCODE_NOTIFICATION:
|
|
case AKEYCODE_SEARCH:
|
|
case AKEYCODE_MEDIA_PLAY_PAUSE:
|
|
case AKEYCODE_MEDIA_STOP:
|
|
case AKEYCODE_MEDIA_NEXT:
|
|
case AKEYCODE_MEDIA_PREVIOUS:
|
|
case AKEYCODE_MEDIA_REWIND:
|
|
case AKEYCODE_MEDIA_FAST_FORWARD:
|
|
case AKEYCODE_MUTE:
|
|
break;
|
|
case AKEYCODE_PAGE_UP:
|
|
return KeyboardButton::page_up();
|
|
case AKEYCODE_PAGE_DOWN:
|
|
return KeyboardButton::page_down();
|
|
case AKEYCODE_PICTSYMBOLS:
|
|
case AKEYCODE_SWITCH_CHARSET:
|
|
case AKEYCODE_BUTTON_A:
|
|
case AKEYCODE_BUTTON_B:
|
|
case AKEYCODE_BUTTON_C:
|
|
case AKEYCODE_BUTTON_X:
|
|
case AKEYCODE_BUTTON_Y:
|
|
case AKEYCODE_BUTTON_Z:
|
|
case AKEYCODE_BUTTON_L1:
|
|
case AKEYCODE_BUTTON_R1:
|
|
case AKEYCODE_BUTTON_L2:
|
|
case AKEYCODE_BUTTON_R2:
|
|
case AKEYCODE_BUTTON_THUMBL:
|
|
case AKEYCODE_BUTTON_THUMBR:
|
|
case AKEYCODE_BUTTON_START:
|
|
case AKEYCODE_BUTTON_SELECT:
|
|
case AKEYCODE_BUTTON_MODE:
|
|
default:
|
|
break;
|
|
}
|
|
return ButtonHandle::none();
|
|
}
|