From bc6c9c709369b6a07b7f691ab6e78eca3621f70f Mon Sep 17 00:00:00 2001 From: seibelj Date: Thu, 5 Jan 2017 16:00:11 -0500 Subject: [PATCH] Added readme and keyboard handler example files --- demo/allegro5/KeyboardHandleriOS.h | 10 +++ demo/allegro5/KeyboardHandleriOS.m | 120 +++++++++++++++++++++++++++++ demo/allegro5/Makefile | 2 - demo/allegro5/Readme.md | 26 +++++++ demo/allegro5/main.c | 31 +++++--- 5 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 demo/allegro5/KeyboardHandleriOS.h create mode 100644 demo/allegro5/KeyboardHandleriOS.m create mode 100644 demo/allegro5/Readme.md diff --git a/demo/allegro5/KeyboardHandleriOS.h b/demo/allegro5/KeyboardHandleriOS.h new file mode 100644 index 0000000..2664d2e --- /dev/null +++ b/demo/allegro5/KeyboardHandleriOS.h @@ -0,0 +1,10 @@ +#import + +#include + +@interface KeyboardHandleriOS : UIView +-(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE*)ev_src; +-(void)show; +-(void)hide; +@end + diff --git a/demo/allegro5/KeyboardHandleriOS.m b/demo/allegro5/KeyboardHandleriOS.m new file mode 100644 index 0000000..206f9e4 --- /dev/null +++ b/demo/allegro5/KeyboardHandleriOS.m @@ -0,0 +1,120 @@ +#ifdef __OBJC__ +#import +#endif +#import "KeyboardHandleriOS.h" +#include +#include +@interface KeyboardHandleriOS() +{ + ALLEGRO_EVENT_SOURCE *event_source; + ALLEGRO_DISPLAY *current_display; +} +@end +@implementation KeyboardHandleriOS +- (id)init { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; + self = [self initWithFrame:CGRectMake(-100, -100, 0, 0)]; + event_source = NULL; + current_display = al_get_current_display(); + UIView* v = al_iphone_get_view(current_display); + [v addSubview:self]; + return self; +} + +- (void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src { + event_source = ev_src; +} + +- (UIKeyboardType) keyboardType +{ + return UIKeyboardTypeASCIICapable; +} + +- (UITextAutocorrectionType) autocorrectionType +{ + return UITextAutocorrectionTypeNo; +} + +-(BOOL)canBecomeFirstResponder { + return YES; +} + +- (void)deleteBackward { + + if (!event_source) { + NSLog(@"deleteBackward(): No event source found, not sending events"); + return; + } + + ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); + ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); + + event_down->type = ALLEGRO_EVENT_KEY_DOWN; + event_down->keyboard.display = current_display; + event_down->keyboard.keycode = ALLEGRO_KEY_BACKSPACE; + event_up->type = ALLEGRO_EVENT_KEY_UP; + event_up->keyboard.display = current_display; + event_up->keyboard.keycode = ALLEGRO_KEY_BACKSPACE; + al_emit_user_event(event_source, event_down, NULL); + al_emit_user_event(event_source, event_up, NULL); + + free(event_down); + free(event_up); +} + +- (BOOL)hasText { + return YES; +} + +- (void)insertText:(NSString *)text +{ + if (!event_source) { + NSLog(@"insertText(): No event source found, not sending events"); + return; + } + + ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); + ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); + + if([text isEqualToString:@"\n"]) + { + event_down->type = ALLEGRO_EVENT_KEY_DOWN; + event_down->keyboard.display = current_display; + event_down->keyboard.keycode = ALLEGRO_KEY_ENTER; + event_up->type = ALLEGRO_EVENT_KEY_UP; + event_up->keyboard.display = current_display; + event_up->keyboard.keycode = ALLEGRO_KEY_ENTER; + al_emit_user_event(event_source, event_down, NULL); + al_emit_user_event(event_source, event_up, NULL); + [self hide]; + //m_kb->setDonePressed(); + } + else { + event_down->type = ALLEGRO_EVENT_KEY_CHAR; + event_down->keyboard.display = current_display; + event_down->keyboard.unichar = [text characterAtIndex:0]; + // doesn't matter what keycode is, nuklear backend ignores it as long as it + // isn't a special key + event_down->keyboard.keycode = ALLEGRO_KEY_A; + al_emit_user_event(event_source, event_down, NULL); + } + free(event_down); + free(event_up); +} + +-(void)show { + NSLog(@"Should be showing!"); + [self performSelectorOnMainThread:@selector(becomeFirstResponder) withObject:nil waitUntilDone:YES]; +} +-(void)hide { + NSLog(@"Should be hiding!"); + [self performSelectorOnMainThread:@selector(resignFirstResponder) withObject:nil waitUntilDone:YES]; +} +- (void)keyboardDidHide:(NSNotification *)notification { + NSLog(@"keyboardDidHide called"); +} + +-(void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil]; +} +@end diff --git a/demo/allegro5/Makefile b/demo/allegro5/Makefile index 68ff64d..8e9e7d4 100644 --- a/demo/allegro5/Makefile +++ b/demo/allegro5/Makefile @@ -3,8 +3,6 @@ BIN = demo # Flags CFLAGS = -std=c99 -pedantic -O2 -# DEBUG -#CFLAGS = -std=c99 -pedantic -O0 -g SRC = main.c OBJ = $(SRC:.c=.o) diff --git a/demo/allegro5/Readme.md b/demo/allegro5/Readme.md new file mode 100644 index 0000000..99bc3b8 --- /dev/null +++ b/demo/allegro5/Readme.md @@ -0,0 +1,26 @@ +# Allegro v5 nuklear backend + +This backend provides support for [Allegro version 5](http://liballeg.org/). It works on on all supported platforms with an OpenGL backend, including iOS and Android. + +Touch support is provided by handling the first touch (ignoring any extra simultaneous touches) and emitting nuklear mouse events. nuklear will handle only the first touch like a single left-mouse click. Dragging the touch screen emits mouse-move events. + +## Compiling +You must link with image, font, ttf, and primitives Allegro addons. See the `Makefile`. + +## Resolutions + +Like every nuklear backend, handling many different resolutions and resolution densities can be tricky. 14px font on a desktop may be perfect, but extremely small on a retina iPad. I recommend writing a middleware that will detect what kind of screen is being used, and modify the sizes of widgets accordingly. + +## Soft Keyboard for Touch Screen Devices +For keyboard support on devices without hardware keyboards (iOS, Android, etc.) you should define `NK_INCLUDE_DYNAMIC_SOFT_KEYBOARD` and pass open and close keyboard functions to `nk_allegro5_init()`. See the `main.c` demo for more information. + +Information on how to implement soft keyboard callbacks for Android can be on the Allegro community wiki: https://wiki.allegro.cc/index.php?title=Running_Allegro_applications_on_Android#Displaying_the_Android_keyboard + +To display a soft keyboard on iOS, you must create a `UIView` subclass that implements the `UIKeyInput` interface. See `KeyboardHandleriOS.h` and `KeyboardHandleriOS.m` Objective-C source code files for an example on how to do this. As the Allegro keyboard driver does not currently listen for iOS events, we use a custom event emitter to emit keyboard events, which is passed in after initialization with `(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src`. This causes normal keyboard events to be emitted and properly caught by the nuklear backend. The provided `main.c` demo file does not implement this, but with the provided source code files it is not difficult to do. See this Allegro community forum thread for more information: https://www.allegro.cc/forums/thread/616672 + +### Manual Soft Keyboard Dismissal +As the user can dismiss a keyboard manually, nuklear will not be aware when this occurs, and the text edit cursor will think the entry field is still active. I recommend catching the dismiss event, then emitting `ALLEGRO_EVENT_TOUCH_BEGIN` and `ALLEGRO_EVENT_TOUCH_END` events in an unused portion of the screen (like the bottom-right corner). This will simulate the user touching outside of the text entry widget, which will make the edit field inactive. + +### The Keyboard Covers Widgets + +If you have a widget near the bottom of the screen, the keyboard opening woll cover it, and the user won't see what they are entering. One way to handle this is to make all text edit widgets view-only, and when tapped you dynamically create a new widget above the keyboard that receives all the key strokes. When the user dismisses the keyboard, copy the result from the new widget into the existing read-only text view and destroy the dynamic one. \ No newline at end of file diff --git a/demo/allegro5/main.c b/demo/allegro5/main.c index 445dd78..6e4a48d 100644 --- a/demo/allegro5/main.c +++ b/demo/allegro5/main.c @@ -19,6 +19,9 @@ #define NK_INCLUDE_STANDARD_IO #define NK_INCLUDE_STANDARD_VARARGS #define NK_INCLUDE_DEFAULT_ALLOCATOR +/* Uncomment this for iOS / Android keyboard support +#define NK_INCLUDE_DYNAMIC_SOFT_KEYBOARD +*/ #define NK_IMPLEMENTATION #define NK_ALLEGRO5_IMPLEMENTATION #include "../../nuklear.h" @@ -51,6 +54,20 @@ static void error_callback(int e, const char *d) {printf("Error %d: %s\n", e, d);} +/* If NK_INCLUDE_DYNAMIC_SOFT_KEYBOARD is enabled, implement these + two methods and pass them as the last 2 arguments to nk_allegro5_init() + to have nuklear call them when appropriate. + +void open_soft_keyboard() +{ + [implement opening keyboard code] +} +void close_soft_keyboard() +{ + [implement close keyboard code] +} +*/ + int main(void) { /* Platform */ @@ -87,19 +104,13 @@ int main(void) al_register_event_source(event_queue, al_get_keyboard_event_source()); NkAllegro5Font *font; - font = nk_allegro5_font_create_from_file("../../extra_font/Roboto-Regular.ttf", 12, 0); + font = nk_allegro5_font_create_from_file("../../../extra_font/Roboto-Regular.ttf", 12, 0); struct nk_context *ctx; + /* If NK_INCLUDE_DYNAMIC_SOFT_KEYBOARD is enabled, pass open_soft_keyboard and + close_soft_keyboard as the last 2 arguments to nk_allegro5_init() instead + of NULL, NULL */ ctx = nk_allegro5_init(font, display, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ /* style.c */ /*set_style(ctx, THEME_WHITE);*/