diff options
| -rw-r--r-- | src/drivers/Android/Fl_Android_Screen_Driver.cxx | 619 |
1 files changed, 24 insertions, 595 deletions
diff --git a/src/drivers/Android/Fl_Android_Screen_Driver.cxx b/src/drivers/Android/Fl_Android_Screen_Driver.cxx index 061658315..7be726938 100644 --- a/src/drivers/Android/Fl_Android_Screen_Driver.cxx +++ b/src/drivers/Android/Fl_Android_Screen_Driver.cxx @@ -173,6 +173,16 @@ int64_t AKeyEvent_getEventTime (const AInputEvent *key_event) AKeyEvent_getScanCode(event)); auto keyAction = AKeyEvent_getAction(event); + if (keyAction==AKEY_EVENT_ACTION_MULTIPLE) { + if (AKeyEvent_getKeyCode(event)==AKEYCODE_UNKNOWN) { + // characters are in getCharacters() + // String class KeyEvent::getCharacters() [Java] + // is there a way to get the true Java event somehow? + // override dispatchKeyEvent(android.view.KeyEvent event) + } else { + // send keycode as many times as getRepeatCount() / AKeyEvent_getRepeatCount(event) + } + } JavaVM *javaVM = Fl_Android_Application::get_activity()->vm; JNIEnv *jniEnv = Fl_Android_Application::get_activity()->env; @@ -182,10 +192,6 @@ int64_t AKeyEvent_getEventTime (const AInputEvent *key_event) if (result == JNI_ERR) return 0; jclass class_key_event = jniEnv->FindClass("android/view/KeyEvent"); - - jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, - "getUnicodeChar", - "(I)I"); jmethodID eventConstructor = jniEnv->GetMethodID(class_key_event, "<init>", "(JJIIIIIIII)V"); jobject eventObj = jniEnv->NewObject(class_key_event, eventConstructor, @@ -199,9 +205,16 @@ int64_t AKeyEvent_getEventTime (const AInputEvent *key_event) AKeyEvent_getScanCode(event), AKeyEvent_getFlags(event), AInputEvent_getSource(event)); + + jmethodID method_get_unicode_char = jniEnv->GetMethodID(class_key_event, + "getUnicodeChar", + "(I)I"); int unicodeKey = jniEnv->CallIntMethod(eventObj, method_get_unicode_char, AKeyEvent_getMetaState(event)); + jniEnv->DeleteLocalRef(class_key_event); + jniEnv->DeleteLocalRef(eventObj); + javaVM->DetachCurrentThread(); static char buf[8]; @@ -224,137 +237,6 @@ int64_t AKeyEvent_getEventTime (const AInputEvent *key_event) } } -/* - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - case WM_KEYUP: - case WM_SYSKEYUP: - // save the keysym until we figure out the characters: - Fl::e_keysym = Fl::e_original_keysym = ms2fltk(wParam, lParam & (1 << 24)); - // See if TranslateMessage turned it into a WM_*CHAR message: - if (PeekMessageW(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { - uMsg = fl_msg.message; - wParam = fl_msg.wParam; - lParam = fl_msg.lParam; - } - // FALLTHROUGH ... - - case WM_DEADCHAR: - case WM_SYSDEADCHAR: - case WM_CHAR: - case WM_SYSCHAR: { - ulong state = Fl::e_state & 0xff000000; // keep the mouse button state - // if GetKeyState is expensive we might want to comment some of these out: - if (GetKeyState(VK_SHIFT) & ~1) - state |= FL_SHIFT; - if (GetKeyState(VK_CAPITAL)) - state |= FL_CAPS_LOCK; - if (GetKeyState(VK_CONTROL) & ~1) - state |= FL_CTRL; - // Alt gets reported for the Alt-GR switch on non-English keyboards. - // so we need to check the event as well to get it right: - if ((lParam & (1 << 29)) // same as GetKeyState(VK_MENU) - && uMsg != WM_CHAR) - state |= FL_ALT; - if (GetKeyState(VK_NUMLOCK)) - state |= FL_NUM_LOCK; - if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & ~1) { - // Windows bug? GetKeyState returns garbage if the user hit the - // meta key to pop up start menu. Sigh. - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & ~1) - state |= FL_META; - } - if (GetKeyState(VK_SCROLL)) - state |= FL_SCROLL_LOCK; - Fl::e_state = state; - static char buffer[1024]; - if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { - wchar_t u = (wchar_t)wParam; - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); - buffer[Fl::e_length] = 0; - } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { - if (state & FL_NUM_LOCK) { - // Convert to regular keypress... - buffer[0] = Fl::e_keysym - FL_KP; - Fl::e_length = 1; - } else { - // Convert to special keypress... - buffer[0] = 0; - Fl::e_length = 0; - switch (Fl::e_keysym) { - case FL_KP + '0': - Fl::e_keysym = FL_Insert; - break; - case FL_KP + '1': - Fl::e_keysym = FL_End; - break; - case FL_KP + '2': - Fl::e_keysym = FL_Down; - break; - case FL_KP + '3': - Fl::e_keysym = FL_Page_Down; - break; - case FL_KP + '4': - Fl::e_keysym = FL_Left; - break; - case FL_KP + '6': - Fl::e_keysym = FL_Right; - break; - case FL_KP + '7': - Fl::e_keysym = FL_Home; - break; - case FL_KP + '8': - Fl::e_keysym = FL_Up; - break; - case FL_KP + '9': - Fl::e_keysym = FL_Page_Up; - break; - case FL_KP + '.': - Fl::e_keysym = FL_Delete; - break; - case FL_KP + '/': - case FL_KP + '*': - case FL_KP + '-': - case FL_KP + '+': - buffer[0] = Fl::e_keysym - FL_KP; - Fl::e_length = 1; - break; - } - } - } else if ((lParam & (1 << 31)) == 0) { -#ifdef FLTK_PREVIEW_DEAD_KEYS - if ((lParam & (1 << 24)) == 0) { // clear if dead key (always?) - wchar_t u = (wchar_t)wParam; - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); - buffer[Fl::e_length] = 0; - } else { // set if "extended key" (never printable?) - buffer[0] = 0; - Fl::e_length = 0; - } -#else - buffer[0] = 0; - Fl::e_length = 0; -#endif - } - Fl::e_text = buffer; - if (lParam & (1 << 31)) { // key up events. - if (Fl::handle(FL_KEYUP, window)) - return 0; - break; - } - while (window->parent()) - window = window->window(); - if (Fl::handle(FL_KEYBOARD, window)) { - if (uMsg == WM_DEADCHAR || uMsg == WM_SYSDEADCHAR) - Fl::compose_state = 1; - return 0; - } - break; // WM_KEYDOWN ... WM_SYSKEYUP, WM_DEADCHAR ... WM_SYSCHAR - } // case WM_DEADCHAR ... WM_SYSCHAR - - */ - - return 0; } @@ -510,223 +392,6 @@ double Fl_Android_Screen_Driver::wait(double time_to_wait) return 0.0; } - -#if 0 - -int Fl_WinAPI_Screen_Driver::visual(int flags) -{ - fl_GetDC(0); - if (flags & FL_DOUBLE) return 0; - HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc(); - if (!(flags & FL_INDEX) && - GetDeviceCaps(gc,BITSPIXEL) <= 8) return 0; - if ((flags & FL_RGB8) && GetDeviceCaps(gc,BITSPIXEL)<24) return 0; - return 1; -} - - -// We go the much more difficult route of individually picking some multi-screen -// functions from the USER32.DLL . If these functions are not available, we -// will gracefully fall back to single monitor support. -// -// If we were to insist on the existence of "EnumDisplayMonitors" and -// "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000 -// before SP2 or earlier. - -// BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM) -typedef BOOL(WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); -// BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO) -typedef BOOL(WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO); - -static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA - - -BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC hdc, LPRECT r, LPARAM d) -{ - Fl_WinAPI_Screen_Driver *drv = (Fl_WinAPI_Screen_Driver*)d; - return drv->screen_cb(mon, hdc, r); -} - - -BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC, LPRECT r) -{ - if (num_screens >= MAX_SCREENS) return TRUE; - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - - // GetMonitorInfo(mon, &mi); - // (but we use our self-acquired function pointer instead) - if (fl_gmi(mon, &mi)) { - screens[num_screens] = mi.rcMonitor; - // If we also want to record the work area, we would also store mi.rcWork at this point - work_area[num_screens] = mi.rcWork; -//extern FILE*LOG;fprintf(LOG,"screen_cb ns=%d\n",num_screens);fflush(LOG); - /*fl_alert("screen %d %d,%d,%d,%d work %d,%d,%d,%d",num_screens, - screens[num_screens].left,screens[num_screens].right,screens[num_screens].top,screens[num_screens].bottom, - work_area[num_screens].left,work_area[num_screens].right,work_area[num_screens].top,work_area[num_screens].bottom); - */ - // find the pixel size - if (mi.cbSize == sizeof(mi)) { - HDC screen = CreateDC(mi.szDevice, NULL, NULL, NULL); - if (screen) { - dpi[num_screens][0] = (float)GetDeviceCaps(screen, LOGPIXELSX); - dpi[num_screens][1] = (float)GetDeviceCaps(screen, LOGPIXELSY); - } - DeleteDC(screen); - } - - num_screens++; - } - return TRUE; -} - - -void Fl_WinAPI_Screen_Driver::init() -{ - open_display(); - // Since not all versions of Windows include multiple monitor support, - // we do a run-time check for the required functions... - HMODULE hMod = GetModuleHandle("USER32.DLL"); - - if (hMod) { - // check that EnumDisplayMonitors is available - fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors"); - - if (fl_edm) { - // we have EnumDisplayMonitors - do we also have GetMonitorInfoA ? - fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA"); - if (fl_gmi) { - // We have GetMonitorInfoA, enumerate all the screens... - // EnumDisplayMonitors(0,0,screen_cb,0); - // (but we use our self-acquired function pointer instead) - // NOTE: num_screens is incremented in screen_cb so we must first reset it here... - num_screens = 0; - fl_edm(0, 0, screen_cb, (LPARAM)this); - return; - } - } - } - - // If we get here, assume we have 1 monitor... - num_screens = 1; - screens[0].top = 0; - screens[0].left = 0; - screens[0].right = GetSystemMetrics(SM_CXSCREEN); - screens[0].bottom = GetSystemMetrics(SM_CYSCREEN); - work_area[0] = screens[0]; - scale_of_screen[0] = 1; -} - - -float Fl_WinAPI_Screen_Driver::desktop_scale_factor() { - return 0; //indicates each screen has already been assigned its scale factor value -} - - -void Fl_WinAPI_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - if (n < 0 || n >= num_screens) n = 0; - X = work_area[n].left/scale_of_screen[n]; - Y = work_area[n].top/scale_of_screen[n]; - W = (work_area[n].right - X)/scale_of_screen[n]; - H = (work_area[n].bottom - Y)/scale_of_screen[n]; -} - - -void Fl_WinAPI_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n) -{ - if (num_screens < 0) init(); - - if ((n < 0) || (n >= num_screens)) - n = 0; - - if (num_screens > 0) { - X = screens[n].left/scale_of_screen[n]; - Y = screens[n].top/scale_of_screen[n]; - W = (screens[n].right - screens[n].left)/scale_of_screen[n]; - H = (screens[n].bottom - screens[n].top)/scale_of_screen[n]; - } else { - /* Fallback if something is broken... */ - X = 0; - Y = 0; - W = GetSystemMetrics(SM_CXSCREEN); - H = GetSystemMetrics(SM_CYSCREEN); - } -} - - -void Fl_WinAPI_Screen_Driver::screen_dpi(float &h, float &v, int n) -{ - if (num_screens < 0) init(); - h = v = 0.0f; - if (n >= 0 && n < num_screens) { - h = float(dpi[n][0]); - v = float(dpi[n][1]); - } -} - - -int Fl_WinAPI_Screen_Driver::x() -{ - RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.left; -} - - -int Fl_WinAPI_Screen_Driver::y() -{ - RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.top; -} - - -int Fl_WinAPI_Screen_Driver::h() -{ - RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.bottom - r.top; -} - - -int Fl_WinAPI_Screen_Driver::w() -{ - RECT r; - - SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - return r.right - r.left; -} - - -void Fl_WinAPI_Screen_Driver::beep(int type) -{ - switch (type) { - case FL_BEEP_QUESTION : - case FL_BEEP_PASSWORD : - MessageBeep(MB_ICONQUESTION); - break; - case FL_BEEP_MESSAGE : - MessageBeep(MB_ICONASTERISK); - break; - case FL_BEEP_NOTIFICATION : - MessageBeep(MB_ICONASTERISK); - break; - case FL_BEEP_ERROR : - MessageBeep(MB_ICONERROR); - break; - default : - MessageBeep(0xFFFFFFFF); - break; - } -} -#endif - /** * On Android, we currently write into a memory buffer and copy * the content to the screen. @@ -741,250 +406,8 @@ void Fl_Android_Screen_Driver::flush() } } -#if 0 -extern void fl_fix_focus(); // in Fl.cxx - -// We have to keep track of whether we have captured the mouse, since -// Windows shows little respect for this... Grep for fl_capture to -// see where and how this is used. -extern HWND fl_capture; - - -void Fl_WinAPI_Screen_Driver::grab(Fl_Window* win) -{ - if (win) { - if (!Fl::grab_) { - SetActiveWindow(fl_capture = fl_xid(Fl::first_window())); - SetCapture(fl_capture); - } - Fl::grab_ = win; - } else { - if (Fl::grab_) { - fl_capture = 0; - ReleaseCapture(); - Fl::grab_ = 0; - fl_fix_focus(); - } - } -} - - -static void set_selection_color(uchar r, uchar g, uchar b) -{ - Fl::set_color(FL_SELECTION_COLOR,r,g,b); -} - - -static void getsyscolor(int what, const char* arg, void (*func)(uchar,uchar,uchar)) -{ - if (arg) { - uchar r,g,b; - if (!fl_parse_color(arg, r,g,b)) - Fl::error("Unknown color: %s", arg); - else - func(r,g,b); - } else { - DWORD x = GetSysColor(what); - func(uchar(x&255), uchar(x>>8), uchar(x>>16)); - } -} - - -void Fl_WinAPI_Screen_Driver::get_system_colors() -{ - if (!bg2_set) getsyscolor(COLOR_WINDOW, fl_bg2,Fl::background2); - if (!fg_set) getsyscolor(COLOR_WINDOWTEXT, fl_fg, Fl::foreground); - if (!bg_set) getsyscolor(COLOR_BTNFACE, fl_bg, Fl::background); - getsyscolor(COLOR_HIGHLIGHT, 0, set_selection_color); -} - - -const char *Fl_WinAPI_Screen_Driver::get_system_scheme() -{ - return fl_getenv("FLTK_SCHEME"); -} - - - - -int Fl_WinAPI_Screen_Driver::compose(int &del) { - unsigned char ascii = (unsigned char)Fl::e_text[0]; - int condition = (Fl::e_state & (FL_ALT | FL_META)) && !(ascii & 128) ; - if (condition) { // this stuff is to be treated as a function key - del = 0; - return 0; - } - del = Fl::compose_state; - Fl::compose_state = 0; - // Only insert non-control characters: - if ( (!Fl::compose_state) && ! (ascii & ~31 && ascii!=127)) { - return 0; - } - return 1; -} - - -Fl_RGB_Image * // O - image or NULL if failed -Fl_WinAPI_Screen_Driver::read_win_rectangle( - int X, // I - Left position - int Y, // I - Top position - int w, // I - Width of area to read - int h) // I - Height of area to read -{ - float s = Fl_Surface_Device::surface()->driver()->scale(); - return read_win_rectangle_unscaled(X*s, Y*s, w*s, h*s); -} - -Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(int X, int Y, int w, int h) -{ - int d = 3; // Depth of image - int alpha = 0; uchar *p = NULL; - // Allocate the image data array as needed... - const uchar *oldp = p; - if (!p) p = new uchar[w * h * d]; - - // Initialize the default colors/alpha in the whole image... - memset(p, alpha, w * h * d); - - // Grab all of the pixels in the image... - - // Assure that we are not trying to read non-existing data. If it is so, the - // function should still work, but the out-of-bounds part of the image is - // untouched (initialized with the alpha value or 0 (black), resp.). - - int ww = w; // We need the original width for output data line size - - int shift_x = 0; // X target shift if X modified - int shift_y = 0; // Y target shift if X modified - - if (X < 0) { - shift_x = -X; - w += X; - X = 0; - } - if (Y < 0) { - shift_y = -Y; - h += Y; - Y = 0; - } - - if (h < 1 || w < 1) return 0/*p*/; // nothing to copy - - int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes) - uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB - - // fill in bitmap info for GetDIBits - - BITMAPINFO bi; - bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = w; - bi.bmiHeader.biHeight = -h; // negative => top-down DIB - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 24; // 24 bits RGB - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = 0; - bi.bmiHeader.biXPelsPerMeter = 0; - bi.bmiHeader.biYPelsPerMeter = 0; - bi.bmiHeader.biClrUsed = 0; - bi.bmiHeader.biClrImportant = 0; - - // copy bitmap from original DC (Window, Fl_Offscreen, ...) - HDC gc = (HDC)fl_graphics_driver->gc(); - HDC hdc = CreateCompatibleDC(gc); - HBITMAP hbm = CreateCompatibleBitmap(gc,w,h); - - int save_dc = SaveDC(hdc); // save context for cleanup - SelectObject(hdc,hbm); // select bitmap - BitBlt(hdc,0,0,w,h,gc,X,Y,SRCCOPY); // copy image section to DDB - - // copy RGB image data to the allocated DIB - - GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS); - - // finally copy the image data to the user buffer - - for (int j = 0; j<h; j++) { - const uchar *src = dib + j * line_size; // source line - uchar *tg = p + (j + shift_y) * d * ww + shift_x * d; // target line - for (int i = 0; i<w; i++) { - uchar b = *src++; - uchar g = *src++; - *tg++ = *src++; // R - *tg++ = g; // G - *tg++ = b; // B - if (alpha) - *tg++ = alpha; // alpha - } - } - - // free used GDI and other structures - - RestoreDC(hdc,save_dc); // reset DC - DeleteDC(hdc); - DeleteObject(hbm); - delete[] dib; // delete DIB temporary buffer - - Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, d); - if (!oldp) rgb->alloc_array = 1; - return rgb; -} - -#ifndef FLTK_HIDPI_SUPPORT -/* Returns the current desktop scaling factor for screen_num (1.75 for example) - */ -float Fl_WinAPI_Screen_Driver::DWM_scaling_factor() { - // Compute the global desktop scaling factor: 1, 1.25, 1.5, 1.75, etc... - // This factor can be set in Windows 10 by - // "Change the size of text, apps and other items" in display settings. - // We don't cache this value because it can change while the app is running. - HDC hdc = GetDC(NULL); - int hr = GetDeviceCaps(hdc, HORZRES); // pixels visible to the app -#ifndef DESKTOPHORZRES -#define DESKTOPHORZRES 118 - /* As of 27 august 2016, the DESKTOPHORZRES flag for GetDeviceCaps() - has disappeared from Microsoft online doc, but is quoted in numerous coding examples - e.g., https://social.msdn.microsoft.com/Forums/en-US/6acc3b21-23a4-4a00-90b4-968a43e1ccc8/capture-screen-with-high-dpi?forum=vbgeneral - It is necessary for the computation of the scaling factor at runtime as done here. - */ -#endif - int dhr = GetDeviceCaps(hdc, DESKTOPHORZRES); // true number of pixels on display - ReleaseDC(NULL, hdc); - float scaling = dhr/float(hr); - scaling = int(scaling * 100 + 0.5)/100.; // round to 2 digits after decimal point - return scaling; -} - -#endif // ! FLTK_HIDPI_SUPPORT - -void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height) -{ - BITMAP bitmap; - if ( GetObject(off, sizeof(BITMAP), &bitmap) ) { - width = bitmap.bmWidth; - height = bitmap.bmHeight; - } -} - -//NOTICE: returns -1 if x,y is not in any screen -int Fl_WinAPI_Screen_Driver::screen_num_unscaled(int x, int y) -{ - int screen = -1; - if (num_screens < 0) init(); - for (int i = 0; i < num_screens; i ++) { - if (x >= screens[i].left && x < screens[i].right && - y >= screens[i].top && y < screens[i].bottom) { - screen = i; - break; - } - } - return screen; -} - -#endif - - -// ---- timers +// ---- timers ----------------------------------------------------------------- struct TimerData { @@ -1130,6 +553,9 @@ void Fl_Android_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void *data) } +// ---- keyboard --------------------------------------------------------------- + + void Fl_Android_Screen_Driver::request_keyboard() { if (pKeyboardCount==0) { @@ -1138,6 +564,9 @@ void Fl_Android_Screen_Driver::request_keyboard() ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT); */ // void displayKeyboard(bool pShow) +// InputMethodManager imm = ( InputMethodManager )getSystemService( Context.INPUT_METHOD_SERVICE ); +// imm.showSoftInput( this.getWindow().getDecorView(), InputMethodManager.SHOW_FORCED ); + bool pShow = true; { // Attaches the current thread to the JVM. |
