| // ImGui iOS+OpenGL+Synergy binding |
| // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. |
| // Providing a standalone iOS application with Synergy integration makes this sample more verbose than others. It also hasn't been tested as much. |
| // Refer to other examples to get an easier understanding of how to integrate ImGui into your existing application. |
| |
| // TODO: |
| // - Clipboard is not supported. |
| |
| #import <OpenGLES/ES3/gl.h> |
| #import <OpenGLES/ES3/glext.h> |
| |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netdb.h> |
| |
| #include "imgui_impl_ios.h" |
| #include "imgui.h" |
| |
| #include "uSynergy.h" |
| |
| // From Carbon HIToolbox/Events.h |
| // FIXME: Keyboard mapping is hacked in because Synergy doesn't give us character but only keycode which aren't really portable if you consider keyboard locale. See https://github.com/ocornut/imgui/pull/247 |
| enum { |
| kVK_ANSI_A = 0x00, |
| kVK_ANSI_S = 0x01, |
| kVK_ANSI_D = 0x02, |
| kVK_ANSI_F = 0x03, |
| kVK_ANSI_H = 0x04, |
| kVK_ANSI_G = 0x05, |
| kVK_ANSI_Z = 0x06, |
| kVK_ANSI_X = 0x07, |
| kVK_ANSI_C = 0x08, |
| kVK_ANSI_V = 0x09, |
| kVK_ANSI_B = 0x0B, |
| kVK_ANSI_Q = 0x0C, |
| kVK_ANSI_W = 0x0D, |
| kVK_ANSI_E = 0x0E, |
| kVK_ANSI_R = 0x0F, |
| kVK_ANSI_Y = 0x10, |
| kVK_ANSI_T = 0x11, |
| kVK_ANSI_1 = 0x12, |
| kVK_ANSI_2 = 0x13, |
| kVK_ANSI_3 = 0x14, |
| kVK_ANSI_4 = 0x15, |
| kVK_ANSI_6 = 0x16, |
| kVK_ANSI_5 = 0x17, |
| kVK_ANSI_Equal = 0x18, |
| kVK_ANSI_9 = 0x19, |
| kVK_ANSI_7 = 0x1A, |
| kVK_ANSI_Minus = 0x1B, |
| kVK_ANSI_8 = 0x1C, |
| kVK_ANSI_0 = 0x1D, |
| kVK_ANSI_RightBracket = 0x1E, |
| kVK_ANSI_O = 0x1F, |
| kVK_ANSI_U = 0x20, |
| kVK_ANSI_LeftBracket = 0x21, |
| kVK_ANSI_I = 0x22, |
| kVK_ANSI_P = 0x23, |
| kVK_ANSI_L = 0x25, |
| kVK_ANSI_J = 0x26, |
| kVK_ANSI_Quote = 0x27, |
| kVK_ANSI_K = 0x28, |
| kVK_ANSI_Semicolon = 0x29, |
| kVK_ANSI_Backslash = 0x2A, |
| kVK_ANSI_Comma = 0x2B, |
| kVK_ANSI_Slash = 0x2C, |
| kVK_ANSI_N = 0x2D, |
| kVK_ANSI_M = 0x2E, |
| kVK_ANSI_Period = 0x2F, |
| kVK_ANSI_Grave = 0x32, |
| kVK_ANSI_KeypadDecimal = 0x41, |
| kVK_ANSI_KeypadMultiply = 0x43, |
| kVK_ANSI_KeypadPlus = 0x45, |
| kVK_ANSI_KeypadClear = 0x47, |
| kVK_ANSI_KeypadDivide = 0x4B, |
| kVK_ANSI_KeypadEnter = 0x4C, |
| kVK_ANSI_KeypadMinus = 0x4E, |
| kVK_ANSI_KeypadEquals = 0x51, |
| kVK_ANSI_Keypad0 = 0x52, |
| kVK_ANSI_Keypad1 = 0x53, |
| kVK_ANSI_Keypad2 = 0x54, |
| kVK_ANSI_Keypad3 = 0x55, |
| kVK_ANSI_Keypad4 = 0x56, |
| kVK_ANSI_Keypad5 = 0x57, |
| kVK_ANSI_Keypad6 = 0x58, |
| kVK_ANSI_Keypad7 = 0x59, |
| kVK_ANSI_Keypad8 = 0x5B, |
| kVK_ANSI_Keypad9 = 0x5C |
| }; |
| |
| /* keycodes for keys that are independent of keyboard layout*/ |
| enum { |
| kVK_Return = 0x24, |
| kVK_Tab = 0x30, |
| kVK_Space = 0x31, |
| kVK_Delete = 0x33, |
| kVK_Escape = 0x35, |
| kVK_Command = 0x37, |
| kVK_Shift = 0x38, |
| kVK_CapsLock = 0x39, |
| kVK_Option = 0x3A, |
| kVK_Control = 0x3B, |
| kVK_RightShift = 0x3C, |
| kVK_RightOption = 0x3D, |
| kVK_RightControl = 0x3E, |
| kVK_Function = 0x3F, |
| kVK_F17 = 0x40, |
| kVK_VolumeUp = 0x48, |
| kVK_VolumeDown = 0x49, |
| kVK_Mute = 0x4A, |
| kVK_F18 = 0x4F, |
| kVK_F19 = 0x50, |
| kVK_F20 = 0x5A, |
| kVK_F5 = 0x60, |
| kVK_F6 = 0x61, |
| kVK_F7 = 0x62, |
| kVK_F3 = 0x63, |
| kVK_F8 = 0x64, |
| kVK_F9 = 0x65, |
| kVK_F11 = 0x67, |
| kVK_F13 = 0x69, |
| kVK_F16 = 0x6A, |
| kVK_F14 = 0x6B, |
| kVK_F10 = 0x6D, |
| kVK_F12 = 0x6F, |
| kVK_F15 = 0x71, |
| kVK_Help = 0x72, |
| kVK_Home = 0x73, |
| kVK_PageUp = 0x74, |
| kVK_ForwardDelete = 0x75, |
| kVK_F4 = 0x76, |
| kVK_End = 0x77, |
| kVK_F2 = 0x78, |
| kVK_PageDown = 0x79, |
| kVK_F1 = 0x7A, |
| kVK_LeftArrow = 0x7B, |
| kVK_RightArrow = 0x7C, |
| kVK_DownArrow = 0x7D, |
| kVK_UpArrow = 0x7E |
| }; |
| |
| static char g_keycodeCharUnshifted[256] = {}; |
| static char g_keycodeCharShifted[256] = {}; |
| |
| //static double g_Time = 0.0f; |
| static bool g_MousePressed[3] = { false, false, false }; |
| static float g_mouseWheelX = 0.0f; |
| static float g_mouseWheelY = 0.0f; |
| |
| static GLuint g_FontTexture = 0; |
| static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; |
| static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; |
| static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; |
| static size_t g_VboSize = 0; |
| static unsigned int g_VboHandle = 0, g_VaoHandle = 0; |
| static float g_displayScale; |
| |
| static int usynergy_sockfd; |
| static bool g_synergyPtrActive = false; |
| static uint16_t g_mousePosX = 0; |
| static uint16_t g_mousePosY = 0; |
| |
| static void ImGui_ImplIOS_RenderDrawLists (ImDrawData *draw_data); |
| bool ImGui_ImplIOS_CreateDeviceObjects(); |
| |
| static NSString *g_serverName; |
| |
| uSynergyBool ImGui_ConnectFunc(uSynergyCookie cookie) |
| { |
| // NOTE: You need to turn off "Use SSL Encryption" in Synergy preferences, since |
| // uSynergy does not support SSL. |
| |
| NSLog( @"Connect Func!"); |
| struct addrinfo hints, *res; |
| |
| // first, load up address structs with getaddrinfo(): |
| memset(&hints, 0, sizeof hints); |
| hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever |
| hints.ai_socktype = SOCK_STREAM; |
| |
| // get server address |
| getaddrinfo([g_serverName UTF8String], "24800", &hints, &res); |
| |
| if (!res) |
| { |
| NSLog( @"Could not find server: %@", g_serverName ); |
| return USYNERGY_FALSE; |
| } |
| |
| // make a socket: |
| usynergy_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); |
| |
| // connect it to the address and port we passed in to getaddrinfo(): |
| int ret = connect(usynergy_sockfd, res->ai_addr, res->ai_addrlen); |
| if (!ret) { |
| NSLog( @"Connect succeeded..."); |
| } else { |
| NSLog( @"Connect failed, %d", ret ); |
| } |
| |
| |
| return USYNERGY_TRUE; |
| } |
| |
| uSynergyBool ImGui_SendFunc(uSynergyCookie cookie, const uint8_t *buffer, int length) |
| { |
| // NSLog( @"Send Func" ); |
| send( usynergy_sockfd, buffer, length, 0 ); |
| |
| return USYNERGY_TRUE; |
| } |
| |
| uSynergyBool ImGui_RecvFunc(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength) |
| { |
| *outLength = (int)recv( usynergy_sockfd, buffer, maxLength, 0 ); |
| |
| return USYNERGY_TRUE; |
| } |
| |
| void ImGui_SleepFunc(uSynergyCookie cookie, int timeMs) |
| { |
| usleep( timeMs * 1000 ); |
| } |
| |
| uint32_t ImGui_GetTimeFunc() |
| { |
| struct timeval tv; |
| gettimeofday(&tv, NULL); |
| |
| return (int32_t)((tv.tv_sec) * 1000 + (tv.tv_usec) / 1000); |
| } |
| |
| void ImGui_TraceFunc(uSynergyCookie cookie, const char *text) |
| { |
| puts(text); |
| } |
| |
| void ImGui_ScreenActiveCallback(uSynergyCookie cookie, uSynergyBool active) |
| { |
| g_synergyPtrActive = active; |
| // printf( "Synergy: screen activate %s\n", active?"YES":"NO" ); |
| } |
| |
| void ImGui_MouseCallback(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, |
| uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle) |
| { |
| // printf("Synergy: mouse callback %d %d -- wheel %d %d\n", x, y, wheelX, wheelY ); |
| uSynergyContext *ctx = (uSynergyContext*)cookie; |
| g_mousePosX = x; |
| g_mousePosY = y; |
| g_mouseWheelX = wheelX; |
| g_mouseWheelY = wheelY; |
| g_MousePressed[0] = buttonLeft; |
| g_MousePressed[1] = buttonMiddle; |
| g_MousePressed[2] = buttonRight; |
| |
| ctx->m_mouseWheelX = 0; |
| ctx->m_mouseWheelY = 0; |
| } |
| |
| void ImGui_KeyboardCallback(uSynergyCookie cookie, uint16_t key, |
| uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) |
| { |
| int scanCode = key-1; |
| // printf("Synergy: keyboard callback: 0x%02X (%s)", scanCode, down?"true":"false"); |
| ImGuiIO& io = ImGui::GetIO(); |
| io.KeysDown[key] = down; |
| io.KeyShift = (modifiers & USYNERGY_MODIFIER_SHIFT); |
| io.KeyCtrl = (modifiers & USYNERGY_MODIFIER_CTRL); |
| io.KeyAlt = (modifiers & USYNERGY_MODIFIER_ALT); |
| io.KeySuper = (modifiers & USYNERGY_MODIFIER_WIN); |
| |
| // Add this as keyboard input |
| if ((down) && (key) && (scanCode<256) && !(modifiers & USYNERGY_MODIFIER_CTRL)) |
| { |
| // If this key maps to a character input, apply it |
| int charForKeycode = (modifiers & USYNERGY_MODIFIER_SHIFT) ? g_keycodeCharShifted[scanCode] : g_keycodeCharUnshifted[scanCode]; |
| io.AddInputCharacter((unsigned short)charForKeycode); |
| } |
| |
| } |
| |
| void ImGui_JoystickCallback(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY) |
| { |
| printf("Synergy: joystick callback TODO\n"); |
| } |
| |
| void ImGui_ClipboardCallback(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size) |
| { |
| printf("Synergy: clipboard callback TODO\n" ); |
| } |
| |
| @interface ImGuiHelper () |
| { |
| BOOL _mouseDown; |
| BOOL _mouseTapped; |
| CGPoint _touchPos; |
| |
| uSynergyContext _synergyCtx; |
| dispatch_queue_t _synergyQueue; |
| } |
| @property (nonatomic, weak) UIView *view; |
| @property (nonatomic, strong) NSString *serverName; |
| |
| @end |
| |
| @implementation ImGuiHelper |
| |
| - (id) initWithView: (UIView *)view |
| { |
| self = [super init]; |
| if (self) |
| { |
| self.view = view; |
| |
| [self setupImGuiHooks]; |
| } |
| return self; |
| } |
| |
| - (void)setupKeymaps |
| { |
| // The keyboard mapping is a big headache. I tried for a while to find a better way to do this, |
| // but this was the best I could come up with. There are some device independent API's available |
| // to convert scan codes to unicode characters, but these are only available on mac and not |
| // on iOS as far as I can tell (it's part of Carbon). I didn't see any better way to do |
| // this or any way to get the character codes out of usynergy. |
| g_keycodeCharUnshifted[ kVK_ANSI_A ]='a'; |
| g_keycodeCharUnshifted[ kVK_ANSI_S ]='s'; |
| g_keycodeCharUnshifted[ kVK_ANSI_D ]='d'; |
| g_keycodeCharUnshifted[ kVK_ANSI_F ]='f'; |
| g_keycodeCharUnshifted[ kVK_ANSI_H ]='h'; |
| g_keycodeCharUnshifted[ kVK_ANSI_G ]='g'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Z ]='z'; |
| g_keycodeCharUnshifted[ kVK_ANSI_X ]='x'; |
| g_keycodeCharUnshifted[ kVK_ANSI_C ]='c'; |
| g_keycodeCharUnshifted[ kVK_ANSI_V ]='v'; |
| g_keycodeCharUnshifted[ kVK_ANSI_B ]='b'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Q ]='q'; |
| g_keycodeCharUnshifted[ kVK_ANSI_W ]='w'; |
| g_keycodeCharUnshifted[ kVK_ANSI_E ]='e'; |
| g_keycodeCharUnshifted[ kVK_ANSI_R ]='r'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Y ]='y'; |
| g_keycodeCharUnshifted[ kVK_ANSI_T ]='t'; |
| g_keycodeCharUnshifted[ kVK_ANSI_1 ]='1'; |
| g_keycodeCharUnshifted[ kVK_ANSI_2 ]='2'; |
| g_keycodeCharUnshifted[ kVK_ANSI_3 ]='3'; |
| g_keycodeCharUnshifted[ kVK_ANSI_4 ]='4'; |
| g_keycodeCharUnshifted[ kVK_ANSI_6 ]='6'; |
| g_keycodeCharUnshifted[ kVK_ANSI_5 ]='5'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Equal ]='='; |
| g_keycodeCharUnshifted[ kVK_ANSI_9 ]='9'; |
| g_keycodeCharUnshifted[ kVK_ANSI_7 ]='7'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Minus ]='-'; |
| g_keycodeCharUnshifted[ kVK_ANSI_8 ]='8'; |
| g_keycodeCharUnshifted[ kVK_ANSI_0 ]='0'; |
| g_keycodeCharUnshifted[ kVK_ANSI_RightBracket ]=']'; |
| g_keycodeCharUnshifted[ kVK_ANSI_O ]='o'; |
| g_keycodeCharUnshifted[ kVK_ANSI_U ]='u'; |
| g_keycodeCharUnshifted[ kVK_ANSI_LeftBracket ]='['; |
| g_keycodeCharUnshifted[ kVK_ANSI_I ]='i'; |
| g_keycodeCharUnshifted[ kVK_ANSI_P ]='p'; |
| g_keycodeCharUnshifted[ kVK_ANSI_L ]='l'; |
| g_keycodeCharUnshifted[ kVK_ANSI_J ]='j'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Quote ]='\''; |
| g_keycodeCharUnshifted[ kVK_ANSI_K ]='k'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Semicolon ]=';'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Backslash ]='\\'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Comma ]=','; |
| g_keycodeCharUnshifted[ kVK_ANSI_Slash ]='/'; |
| g_keycodeCharUnshifted[ kVK_ANSI_N ]='n'; |
| g_keycodeCharUnshifted[ kVK_ANSI_M ]='m'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Period ]='.'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Grave ]='`'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadDecimal ]='.'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadMultiply ]='*'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadPlus ]='+'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadDivide ]='/'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadEnter ]='\n'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadMinus ]='-'; |
| g_keycodeCharUnshifted[ kVK_ANSI_KeypadEquals ]='='; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad0 ]='0'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad1 ]='1'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad2 ]='2'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad3 ]='3'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad4 ]='4'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad5 ]='5'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad6 ]='6'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad7 ]='7'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad8 ]='8'; |
| g_keycodeCharUnshifted[ kVK_ANSI_Keypad9 ]='9'; |
| g_keycodeCharUnshifted[ kVK_Space ]=' '; |
| |
| g_keycodeCharShifted[ kVK_ANSI_A ]='A'; |
| g_keycodeCharShifted[ kVK_ANSI_S ]='S'; |
| g_keycodeCharShifted[ kVK_ANSI_D ]='D'; |
| g_keycodeCharShifted[ kVK_ANSI_F ]='F'; |
| g_keycodeCharShifted[ kVK_ANSI_H ]='H'; |
| g_keycodeCharShifted[ kVK_ANSI_G ]='G'; |
| g_keycodeCharShifted[ kVK_ANSI_Z ]='Z'; |
| g_keycodeCharShifted[ kVK_ANSI_X ]='X'; |
| g_keycodeCharShifted[ kVK_ANSI_C ]='C'; |
| g_keycodeCharShifted[ kVK_ANSI_V ]='V'; |
| g_keycodeCharShifted[ kVK_ANSI_B ]='B'; |
| g_keycodeCharShifted[ kVK_ANSI_Q ]='Q'; |
| g_keycodeCharShifted[ kVK_ANSI_W ]='W'; |
| g_keycodeCharShifted[ kVK_ANSI_E ]='E'; |
| g_keycodeCharShifted[ kVK_ANSI_R ]='R'; |
| g_keycodeCharShifted[ kVK_ANSI_Y ]='Y'; |
| g_keycodeCharShifted[ kVK_ANSI_T ]='T'; |
| g_keycodeCharShifted[ kVK_ANSI_1 ]='!'; |
| g_keycodeCharShifted[ kVK_ANSI_2 ]='@'; |
| g_keycodeCharShifted[ kVK_ANSI_3 ]='#'; |
| g_keycodeCharShifted[ kVK_ANSI_4 ]='$'; |
| g_keycodeCharShifted[ kVK_ANSI_6 ]='^'; |
| g_keycodeCharShifted[ kVK_ANSI_5 ]='%'; |
| g_keycodeCharShifted[ kVK_ANSI_Equal ]='+'; |
| g_keycodeCharShifted[ kVK_ANSI_9 ]='('; |
| g_keycodeCharShifted[ kVK_ANSI_7 ]='&'; |
| g_keycodeCharShifted[ kVK_ANSI_Minus ]='_'; |
| g_keycodeCharShifted[ kVK_ANSI_8 ]='*'; |
| g_keycodeCharShifted[ kVK_ANSI_0 ]=')'; |
| g_keycodeCharShifted[ kVK_ANSI_RightBracket ]='}'; |
| g_keycodeCharShifted[ kVK_ANSI_O ]='O'; |
| g_keycodeCharShifted[ kVK_ANSI_U ]='U'; |
| g_keycodeCharShifted[ kVK_ANSI_LeftBracket ]='{'; |
| g_keycodeCharShifted[ kVK_ANSI_I ]='I'; |
| g_keycodeCharShifted[ kVK_ANSI_P ]='P'; |
| g_keycodeCharShifted[ kVK_ANSI_L ]='L'; |
| g_keycodeCharShifted[ kVK_ANSI_J ]='J'; |
| g_keycodeCharShifted[ kVK_ANSI_Quote ]='\"'; |
| g_keycodeCharShifted[ kVK_ANSI_K ]='K'; |
| g_keycodeCharShifted[ kVK_ANSI_Semicolon ]=':'; |
| g_keycodeCharShifted[ kVK_ANSI_Backslash ]='|'; |
| g_keycodeCharShifted[ kVK_ANSI_Comma ]='<'; |
| g_keycodeCharShifted[ kVK_ANSI_Slash ]='?'; |
| g_keycodeCharShifted[ kVK_ANSI_N ]='N'; |
| g_keycodeCharShifted[ kVK_ANSI_M ]='M'; |
| g_keycodeCharShifted[ kVK_ANSI_Period ]='>'; |
| g_keycodeCharShifted[ kVK_ANSI_Grave ]='~'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadDecimal ]='.'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadMultiply ]='*'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadPlus ]='+'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadDivide ]='/'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadEnter ]='\n'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadMinus ]='-'; |
| g_keycodeCharShifted[ kVK_ANSI_KeypadEquals ]='='; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad0 ]='0'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad1 ]='1'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad2 ]='2'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad3 ]='3'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad4 ]='4'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad5 ]='5'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad6 ]='6'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad7 ]='7'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad8 ]='8'; |
| g_keycodeCharShifted[ kVK_ANSI_Keypad9 ]='9'; |
| g_keycodeCharShifted[ kVK_Space ]=' '; |
| } |
| |
| - (void)setupImGuiHooks |
| { |
| ImGuiIO &io = ImGui::GetIO(); |
| |
| [self setupKeymaps]; |
| |
| // Account for retina display for glScissor |
| g_displayScale = [[UIScreen mainScreen] scale]; |
| |
| ImGuiStyle &style = ImGui::GetStyle(); |
| style.TouchExtraPadding = ImVec2( 4.0, 4.0 ); |
| |
| io.RenderDrawListsFn = ImGui_ImplIOS_RenderDrawLists; |
| |
| UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidPan:) ]; |
| [self.view addGestureRecognizer:panRecognizer]; |
| |
| UITapGestureRecognizer *tapRecoginzer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector( viewDidTap:)]; |
| [self.view addGestureRecognizer:tapRecoginzer]; |
| |
| // Fill out the Synergy key map |
| // (for some reason synergy scan codes are off by 1) |
| io.KeyMap[ImGuiKey_Tab] = kVK_Tab+1; |
| io.KeyMap[ImGuiKey_LeftArrow] = kVK_LeftArrow+1; |
| io.KeyMap[ImGuiKey_RightArrow] = kVK_RightArrow+1; |
| io.KeyMap[ImGuiKey_UpArrow] = kVK_UpArrow+1; |
| io.KeyMap[ImGuiKey_DownArrow] = kVK_DownArrow+1; |
| io.KeyMap[ImGuiKey_Home] = kVK_Home+1; |
| io.KeyMap[ImGuiKey_End] = kVK_End+1; |
| io.KeyMap[ImGuiKey_Insert] = kVK_Help+1; |
| io.KeyMap[ImGuiKey_Delete] = kVK_ForwardDelete+1; |
| io.KeyMap[ImGuiKey_Backspace] = kVK_Delete+1; |
| io.KeyMap[ImGuiKey_Space] = kVK_Space+1; |
| io.KeyMap[ImGuiKey_Enter] = kVK_Return+1; |
| io.KeyMap[ImGuiKey_Escape] = kVK_Escape+1; |
| io.KeyMap[ImGuiKey_A] = kVK_ANSI_A+1; |
| io.KeyMap[ImGuiKey_C] = kVK_ANSI_C+1; |
| io.KeyMap[ImGuiKey_V] = kVK_ANSI_V+1; |
| io.KeyMap[ImGuiKey_X] = kVK_ANSI_X+1; |
| io.KeyMap[ImGuiKey_Y] = kVK_ANSI_Y+1; |
| io.KeyMap[ImGuiKey_Z] = kVK_ANSI_Z+1; |
| } |
| |
| - (void)connectServer: (NSString*)serverName |
| { |
| self.serverName = serverName; |
| g_serverName = serverName; |
| |
| // Init synergy |
| NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey]; |
| |
| uSynergyInit( &_synergyCtx ); |
| _synergyCtx.m_clientName = strdup( [bundleName UTF8String] ); |
| _synergyCtx.m_clientWidth = self.view.bounds.size.width; |
| _synergyCtx.m_clientHeight = self.view.bounds.size.height; |
| |
| _synergyCtx.m_connectFunc = ImGui_ConnectFunc; |
| _synergyCtx.m_sendFunc = ImGui_SendFunc; |
| _synergyCtx.m_receiveFunc = ImGui_RecvFunc; |
| _synergyCtx.m_sleepFunc = ImGui_SleepFunc; |
| _synergyCtx.m_traceFunc = ImGui_TraceFunc; |
| _synergyCtx.m_getTimeFunc = ImGui_GetTimeFunc; |
| |
| _synergyCtx.m_traceFunc = ImGui_TraceFunc; |
| _synergyCtx.m_screenActiveCallback = ImGui_ScreenActiveCallback; |
| _synergyCtx.m_mouseCallback = ImGui_MouseCallback; |
| _synergyCtx.m_keyboardCallback = ImGui_KeyboardCallback; |
| |
| _synergyCtx.m_cookie = (uSynergyCookie)&_synergyCtx; |
| |
| // Create a background thread for synergy |
| _synergyQueue = dispatch_queue_create( "imgui-usynergy", NULL ); |
| dispatch_async( _synergyQueue, ^{ |
| while (1) { |
| uSynergyUpdate( &_synergyCtx ); |
| } |
| }); |
| } |
| |
| |
| - (void)viewDidPan: (UIPanGestureRecognizer *)recognizer |
| { |
| |
| if ((recognizer.state == UIGestureRecognizerStateBegan) || |
| (recognizer.state == UIGestureRecognizerStateChanged)) |
| { |
| _mouseDown = YES; |
| _touchPos = [recognizer locationInView:self.view]; |
| } |
| else |
| { |
| _mouseDown = NO; |
| _touchPos = CGPointMake( -1, -1 ); |
| } |
| } |
| |
| - (void)viewDidTap: (UITapGestureRecognizer*)recognizer |
| { |
| _touchPos = [recognizer locationInView:self.view]; |
| _mouseTapped = YES; |
| } |
| |
| - (void)render |
| { |
| ImGui::Render(); |
| } |
| |
| - (void)newFrame |
| { |
| ImGuiIO& io = ImGui::GetIO(); |
| ImGuiStyle &style = ImGui::GetStyle(); |
| |
| if (!g_FontTexture) |
| { |
| ImGui_ImplIOS_CreateDeviceObjects(); |
| } |
| |
| io.DisplaySize = ImVec2( _view.bounds.size.width, _view.bounds.size.height ); |
| |
| io.MouseDrawCursor = g_synergyPtrActive; |
| if (g_synergyPtrActive) |
| { |
| style.TouchExtraPadding = ImVec2( 0.0, 0.0 ); |
| io.MousePos = ImVec2( g_mousePosX, g_mousePosY ); |
| for (int i=0; i < 3; i++) |
| { |
| io.MouseDown[i] = g_MousePressed[i]; |
| } |
| |
| // This is an arbitrary scaling factor that works for me. Not sure what units these mousewheel values from synergy are supposed to be in. |
| io.MouseWheel = g_mouseWheelY / 500.0; |
| io.MouseWheelH = g_mouseWheelX / 500.0; |
| } |
| else |
| { |
| // Synergy not active, use touch events |
| style.TouchExtraPadding = ImVec2( 4.0, 4.0 ); |
| io.MousePos = ImVec2(_touchPos.x, _touchPos.y ); |
| if ((_mouseDown) || (_mouseTapped)) |
| { |
| io.MouseDown[0] = true; |
| _mouseTapped = NO; |
| } |
| else |
| { |
| io.MouseDown[0] = false; |
| } |
| } |
| |
| ImGui::NewFrame(); |
| } |
| @end |
| |
| // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) |
| // If text or lines are blurry when integrating ImGui in your engine: |
| // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) |
| // NOTE: this is copied pretty much entirely from the opengl3_example, with only minor changes for ES |
| static void ImGui_ImplIOS_RenderDrawLists (ImDrawData *draw_data) |
| { |
| // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled |
| // FIXME: Backport changes from imgui_impl_glfw_gl3.cpp |
| GLint last_program, last_texture; |
| glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); |
| glEnable(GL_BLEND); |
| glBlendEquation(GL_FUNC_ADD); |
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| |
| glDisable(GL_CULL_FACE); |
| glDisable(GL_DEPTH_TEST); |
| glEnable(GL_SCISSOR_TEST); |
| glActiveTexture(GL_TEXTURE0); |
| |
| // Setup orthographic projection matrix |
| const float width = ImGui::GetIO().DisplaySize.x; |
| const float height = ImGui::GetIO().DisplaySize.y; |
| const float ortho_projection[4][4] = |
| { |
| { 2.0f/width, 0.0f, 0.0f, 0.0f }, |
| { 0.0f, 2.0f/-height, 0.0f, 0.0f }, |
| { 0.0f, 0.0f, -1.0f, 0.0f }, |
| { -1.0f, 1.0f, 0.0f, 1.0f }, |
| }; |
| glUseProgram(g_ShaderHandle); |
| glUniform1i(g_AttribLocationTex, 0); |
| glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); |
| glBindVertexArray(g_VaoHandle); |
| |
| for (int n = 0; n < draw_data->CmdListsCount; n++) |
| { |
| ImDrawList* cmd_list = draw_data->CmdLists[n]; |
| ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front(); |
| |
| glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); |
| const int needed_vtx_size = cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); |
| if (g_VboSize < needed_vtx_size) |
| { |
| // Grow our buffer if needed |
| g_VboSize = needed_vtx_size + 2000 * sizeof(ImDrawVert); |
| glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)g_VboSize, NULL, GL_STREAM_DRAW); |
| } |
| |
| unsigned char* vtx_data = (unsigned char*)glMapBufferRange(GL_ARRAY_BUFFER, 0, needed_vtx_size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); |
| if (!vtx_data) |
| continue; |
| memcpy(vtx_data, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); |
| glUnmapBuffer(GL_ARRAY_BUFFER); |
| |
| for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) |
| { |
| const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; |
| if (pcmd->UserCallback) |
| { |
| pcmd->UserCallback(cmd_list, pcmd); |
| } |
| else |
| { |
| glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); |
| glScissor((int)(pcmd->ClipRect.x * g_displayScale), |
| (int)((height - pcmd->ClipRect.w) * g_displayScale), |
| (int)((pcmd->ClipRect.z - pcmd->ClipRect.x) * g_displayScale), |
| (int)((pcmd->ClipRect.w - pcmd->ClipRect.y) * g_displayScale)); |
| glDrawElements( GL_TRIANGLES, (GLsizei)pcmd->ElemCount, GL_UNSIGNED_SHORT, idx_buffer ); |
| } |
| idx_buffer += pcmd->ElemCount; |
| } |
| } |
| |
| // Restore modified state |
| glBindVertexArray(0); |
| glBindBuffer( GL_ARRAY_BUFFER, 0); |
| glEnable(GL_CULL_FACE); |
| glEnable(GL_DEPTH_TEST); |
| glUseProgram(last_program); |
| glDisable(GL_SCISSOR_TEST); |
| glBindTexture(GL_TEXTURE_2D, last_texture); |
| } |
| |
| void ImGui_ImplIOS_CreateFontsTexture() |
| { |
| // Build texture atlas |
| ImGuiIO& io = ImGui::GetIO(); |
| unsigned char* pixels; |
| int width, height; |
| io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. |
| |
| // Upload texture to graphics system |
| GLint last_texture; |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); |
| glGenTextures(1, &g_FontTexture); |
| glBindTexture(GL_TEXTURE_2D, g_FontTexture); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| |
| // Store our identifier |
| io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; |
| |
| // Restore state |
| glBindTexture(GL_TEXTURE_2D, last_texture); |
| } |
| |
| bool ImGui_ImplIOS_CreateDeviceObjects() |
| { |
| const GLchar *vertex_shader = |
| "uniform mat4 ProjMtx;\n" |
| "attribute highp vec2 Position;\n" |
| "attribute highp vec2 UV;\n" |
| "attribute highp vec4 Color;\n" |
| "varying vec2 Frag_UV;\n" |
| "varying vec4 Frag_Color;\n" |
| "void main()\n" |
| "{\n" |
| " Frag_UV = UV;\n" |
| " Frag_Color = Color;\n" |
| " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" |
| "}\n"; |
| |
| const GLchar* fragment_shader = |
| "uniform sampler2D Texture;\n" |
| "varying highp vec2 Frag_UV;\n" |
| "varying highp vec4 Frag_Color;\n" |
| "void main()\n" |
| "{\n" |
| " gl_FragColor = Frag_Color * texture2D( Texture, Frag_UV.st);\n" |
| "}\n"; |
| |
| g_ShaderHandle = glCreateProgram(); |
| g_VertHandle = glCreateShader(GL_VERTEX_SHADER); |
| g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); |
| glShaderSource(g_VertHandle, 1, &vertex_shader, 0); |
| glShaderSource(g_FragHandle, 1, &fragment_shader, 0); |
| glCompileShader(g_VertHandle); |
| |
| #if defined(DEBUG) |
| GLint logLength; |
| glGetShaderiv( g_VertHandle, GL_INFO_LOG_LENGTH, &logLength); |
| if (logLength > 0) { |
| GLchar *log = (GLchar *)malloc(logLength); |
| glGetShaderInfoLog(g_VertHandle, logLength, &logLength, log); |
| NSLog(@"VERTEX Shader compile log:\n%s", log); |
| free(log); |
| } |
| #endif |
| |
| glCompileShader(g_FragHandle); |
| |
| #if defined(DEBUG) |
| glGetShaderiv( g_FragHandle, GL_INFO_LOG_LENGTH, &logLength); |
| if (logLength > 0) { |
| GLchar *log = (GLchar *)malloc(logLength); |
| glGetShaderInfoLog(g_FragHandle, logLength, &logLength, log); |
| NSLog(@"FRAGMENT Shader compile log:\n%s", log); |
| free(log); |
| } |
| #endif |
| |
| glAttachShader(g_ShaderHandle, g_VertHandle); |
| glAttachShader(g_ShaderHandle, g_FragHandle); |
| glLinkProgram(g_ShaderHandle); |
| |
| g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); |
| g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); |
| g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); |
| g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); |
| g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); |
| |
| glGenBuffers(1, &g_VboHandle); |
| |
| glGenVertexArrays(1, &g_VaoHandle); |
| glBindVertexArray(g_VaoHandle); |
| glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); |
| glEnableVertexAttribArray(g_AttribLocationPosition); |
| glEnableVertexAttribArray(g_AttribLocationUV); |
| glEnableVertexAttribArray(g_AttribLocationColor); |
| |
| glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); |
| glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); |
| glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); |
| |
| glBindVertexArray(0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| ImGui_ImplIOS_CreateFontsTexture(); |
| |
| return true; |
| } |