static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { struct vo_wayland_state *wl = data; uint32_t code, num_syms; int mpkey; const xkb_keysym_t *syms; xkb_keysym_t sym; code = key + 8; num_syms = xkb_key_get_syms(wl->input.xkb.state, code, &syms); sym = XKB_KEY_NoSymbol; if (num_syms == 1) sym = syms[0]; if (sym != XKB_KEY_NoSymbol && (mpkey = lookupkey(sym))) { if (state == WL_KEYBOARD_KEY_STATE_PRESSED) mp_input_put_key(wl->vo->input_ctx, mpkey | MP_KEY_STATE_DOWN); else mp_input_put_key(wl->vo->input_ctx, mpkey | MP_KEY_STATE_UP); } }
static void read_input(void) { DWORD retval; HANDLE in = GetStdHandle(STD_INPUT_HANDLE); /*check if there are input events*/ if (!GetNumberOfConsoleInputEvents(in, &retval)) return; if (!retval) return; /*read all events*/ INPUT_RECORD eventbuffer[128]; if (!ReadConsoleInput(in, eventbuffer, MP_ARRAY_SIZE(eventbuffer), &retval)) return; /*filter out keyevents*/ for (int i = 0; i < retval; i++) { switch (eventbuffer[i].EventType) { case KEY_EVENT: { KEY_EVENT_RECORD *record = &eventbuffer[i].Event.KeyEvent; /*only a pressed key is interesting for us*/ if (record->bKeyDown) { UINT vkey = record->wVirtualKeyCode; bool ext = record->dwControlKeyState & ENHANCED_KEY; int mpkey = mp_w32_vkey_to_mpkey(vkey, ext); if (mpkey) { mp_input_put_key(input_ctx, mpkey); } else { /*only characters should be remaining*/ int c = record->uChar.UnicodeChar; if (c > 0) mp_input_put_key(input_ctx, c); } } break; } case MOUSE_EVENT: case WINDOW_BUFFER_SIZE_EVENT: case FOCUS_EVENT: case MENU_EVENT: default: break; } } return; }
/** * \brief Dispatch incoming window events and handle them. * * This function should be placed inside libvo's function "check_events". * * \return int with these flags possibly set, take care to handle in the right order * if it matters in your driver: * * VO_EVENT_RESIZE = The window was resized. If necessary reinit your * driver render context accordingly. * VO_EVENT_EXPOSE = The window was exposed. Call e.g. flip_frame() to redraw * the window if the movie is paused. */ int vo_w32_check_events(struct vo *vo) { struct vo_w32_state *w32 = vo->w32; MSG msg; w32->event_flags = 0; while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageW(&msg); } if (vo->opts->WinID >= 0) { BOOL res; RECT r; POINT p; res = GetClientRect(w32->window, &r); if (res && (r.right != vo->dwidth || r.bottom != vo->dheight)) { vo->dwidth = r.right; vo->dheight = r.bottom; w32->event_flags |= VO_EVENT_RESIZE; } p.x = 0; p.y = 0; ClientToScreen(w32->window, &p); if (p.x != w32->window_x || p.y != w32->window_y) { w32->window_x = p.x; w32->window_y = p.y; } res = GetClientRect(WIN_ID_TO_HWND(vo->opts->WinID), &r); if (res && (r.right != vo->dwidth || r.bottom != vo->dheight)) MoveWindow(w32->window, 0, 0, r.right, r.bottom, FALSE); if (!IsWindow(WIN_ID_TO_HWND(vo->opts->WinID))) // Window has probably been closed, e.g. due to program crash mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN); } return w32->event_flags; }
static void pointer_handle_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { struct vo_wayland_state *wl = data; mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_LEAVE); }
static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { struct vo_wayland_state *wl = data; mp_input_put_key(wl->vo->input_ctx, MP_MOUSE_BTN0 + (button - BTN_LEFT) | ((state == WL_POINTER_BUTTON_STATE_PRESSED) ? MP_KEY_STATE_DOWN : MP_KEY_STATE_UP)); if ((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) wl_shell_surface_move(wl->window.shell_surface, wl->input.seat, serial); }
/* POINTER LISTENER */ static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx_w, wl_fixed_t sy_w) { struct vo_wayland_state *wl = data; wl->cursor.serial = serial; wl->cursor.pointer = pointer; /* Release the left button on pointer enter again * because after moving the shell surface no release event is sent */ mp_input_put_key(wl->vo->input_ctx, MP_MOUSE_BTN0 | MP_KEY_STATE_UP); show_cursor(wl); }
bool getch2(struct input_ctx *input_ctx) { int retval = read(0, &getch2_buf[getch2_pos], BUF_LEN - getch2_len - getch2_pos); /* Return false on EOF to stop running select() on the FD, as it'd * trigger all the time. Note that it's possible to get temporary * EOF on terminal if the user presses ctrl-d, but that shouldn't * happen if the terminal state change done in getch2_enable() * works. */ if (retval == 0) return false; if (retval == -1) return errno != EBADF && errno != EINVAL; getch2_len += retval; while (getch2_pos < getch2_len) { unsigned char c = getch2_buf[getch2_pos++]; switch (state) { case STATE_INITIAL: { int match_count = keys_count_matches(&getch2_buf[0], getch2_len); if (match_count == 1) { keycode_st *st = keys_search(&getch2_buf[0], getch2_len); if (st) { mp_input_put_key(input_ctx, st->code); walk_buf(st->len); } /* else this is still a partial (but unique) match */ continue; } else if (match_count > 1) { continue; /* need more bytes to disambiguate */ } else { /* backtrack, send as UTF-8 */ getch2_pos = 1; c = getch2_buf[0]; } utf8_len = bstr_parse_utf8_code_length(c); if (utf8_len > 1) { state = STATE_UTF8; } else if (utf8_len == 1) { switch (c) { case 0x1b: /* ESC that's not part of escape sequence */ /* only if ESC was typed twice, otherwise ignore it */ if (getch2_len > 1 && getch2_buf[1] == 0x1b) { walk_buf(1); /* eat the second ESC */ mp_input_put_key(input_ctx, MP_KEY_ESC); } break; default: mp_input_put_key(input_ctx, c); } walk_buf(1); } else walk_buf(getch2_pos); break; } case STATE_UTF8: { if (getch2_pos < utf8_len) /* need more bytes */ continue; struct bstr s = {getch2_buf, utf8_len}; int unicode = bstr_decode_utf8(s, NULL); if (unicode > 0) { mp_input_put_key(input_ctx, unicode); } walk_buf(utf8_len); state = STATE_INITIAL; continue; } } } return true; }
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_NCCREATE) { CREATESTRUCT *cs = (void*)lParam; SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams); } struct vo *vo = (void*)GetWindowLongPtrW(hWnd, GWLP_USERDATA); // message before WM_NCCREATE, pray to Raymond Chen that it's not important if (!vo) return DefWindowProcW(hWnd, message, wParam, lParam); struct vo_w32_state *w32 = vo->w32; int mouse_button = 0; switch (message) { case WM_ERASEBKGND: // no need to erase background seperately return 1; case WM_PAINT: w32->event_flags |= VO_EVENT_EXPOSE; break; case WM_MOVE: { POINT p = {0}; ClientToScreen(w32->window, &p); w32->window_x = p.x; w32->window_y = p.y; MP_VERBOSE(vo, "move window: %d:%d\n", w32->window_x, w32->window_y); break; } case WM_SIZE: { w32->event_flags |= VO_EVENT_RESIZE; RECT r; GetClientRect(w32->window, &r); vo->dwidth = r.right; vo->dheight = r.bottom; MP_VERBOSE(vo, "resize window: %d:%d\n", vo->dwidth, vo->dheight); break; } case WM_SIZING: if (vo->opts->keepaspect && !vo->opts->fullscreen && vo->opts->WinID < 0) { RECT *rc = (RECT*)lParam; // get client area of the windows if it had the rect rc // (subtracting the window borders) RECT r = *rc; subtract_window_borders(w32->window, &r); int c_w = r.right - r.left, c_h = r.bottom - r.top; float aspect = w32->o_dwidth / (float) MPMAX(w32->o_dheight, 1); int d_w = c_h * aspect - c_w; int d_h = c_w / aspect - c_h; int d_corners[4] = { d_w, d_h, -d_w, -d_h }; int corners[4] = { rc->left, rc->top, rc->right, rc->bottom }; int corner = get_resize_border(wParam); if (corner >= 0) corners[corner] -= d_corners[corner]; *rc = (RECT) { corners[0], corners[1], corners[2], corners[3] }; return TRUE; } break; case WM_CLOSE: mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN); break; case WM_SYSCOMMAND: switch (wParam) { case SC_SCREENSAVE: case SC_MONITORPOWER: if (w32->disable_screensaver) { MP_VERBOSE(vo, "win32: killing screensaver\n"); return 0; } break; } break; case WM_KEYDOWN: case WM_SYSKEYDOWN: { int mpkey = lookup_keymap_table(vk_map, wParam); if (mpkey) mp_input_put_key(vo->input_ctx, mpkey | mod_state(vo)); if (wParam == VK_F10) return 0; break; } case WM_CHAR: case WM_SYSCHAR: { int mods = mod_state(vo); int code = wParam; // Windows enables Ctrl+Alt when AltGr (VK_RMENU) is pressed. // E.g. AltGr+9 on a German keyboard would yield Ctrl+Alt+[ // Warning: wine handles this differently. Don't test this on wine! if (key_state(vo, VK_RMENU) && mp_input_use_alt_gr(vo->input_ctx)) mods &= ~(MP_KEY_MODIFIER_CTRL | MP_KEY_MODIFIER_ALT); // Apparently Ctrl+A to Ctrl+Z is special cased, and produces // character codes from 1-26. Work it around. // Also, enter/return (including the keypad variant) and CTRL+J both // map to wParam==10. As a workaround, check VK_RETURN to // distinguish these two key combinations. if ((mods & MP_KEY_MODIFIER_CTRL) && code >= 1 && code <= 26 && !key_state(vo, VK_RETURN)) code = code - 1 + (mods & MP_KEY_MODIFIER_SHIFT ? 'A' : 'a'); if (code >= 32 && code < (1<<21)) { mp_input_put_key(vo->input_ctx, code | mods); // At least with Alt+char, not calling DefWindowProcW stops // Windows from emitting a beep. return 0; } break; } case WM_SETCURSOR: if (LOWORD(lParam) == HTCLIENT && !w32->cursor_visible) { SetCursor(NULL); return TRUE; } break; case WM_MOUSELEAVE: w32->tracking = FALSE; mp_input_put_key(vo->input_ctx, MP_KEY_MOUSE_LEAVE); break; case WM_MOUSEMOVE: { if (!w32->tracking) w32->tracking = TrackMouseEvent(&w32->trackEvent); // Windows can send spurious mouse events, which would make the mpv // core unhide the mouse cursor on completely unrelated events. See: // https://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); if (x != w32->mouse_x || y != w32->mouse_y) { w32->mouse_x = x; w32->mouse_y = y; vo_mouse_movement(vo, x, y); } break; } case WM_LBUTTONDOWN: mouse_button = MP_MOUSE_BTN0 | MP_KEY_STATE_DOWN; break; case WM_LBUTTONUP: mouse_button = MP_MOUSE_BTN0 | MP_KEY_STATE_UP; break; case WM_MBUTTONDOWN: mouse_button = MP_MOUSE_BTN1 | MP_KEY_STATE_DOWN; break; case WM_MBUTTONUP: mouse_button = MP_MOUSE_BTN1 | MP_KEY_STATE_UP; break; case WM_RBUTTONDOWN: mouse_button = MP_MOUSE_BTN2 | MP_KEY_STATE_DOWN; break; case WM_RBUTTONUP: mouse_button = MP_MOUSE_BTN2 | MP_KEY_STATE_UP; break; case WM_MOUSEWHEEL: { int x = GET_WHEEL_DELTA_WPARAM(wParam); mouse_button = x > 0 ? MP_MOUSE_BTN3 : MP_MOUSE_BTN4; break; } case WM_XBUTTONDOWN: mouse_button = HIWORD(wParam) == 1 ? MP_MOUSE_BTN5 : MP_MOUSE_BTN6; mouse_button |= MP_KEY_STATE_DOWN; break; case WM_XBUTTONUP: mouse_button = HIWORD(wParam) == 1 ? MP_MOUSE_BTN5 : MP_MOUSE_BTN6; mouse_button |= MP_KEY_STATE_UP; break; } if (mouse_button && vo->opts->enable_mouse_movements) { int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); mouse_button |= mod_state(vo); if (mouse_button == (MP_MOUSE_BTN0 | MP_KEY_STATE_DOWN) && !vo->opts->fullscreen && !mp_input_test_dragging(vo->input_ctx, x, y)) { // Window dragging hack ReleaseCapture(); SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); return 0; } mp_input_put_key(vo->input_ctx, mouse_button); } return DefWindowProcW(hWnd, message, wParam, lParam); }
static void check_events(struct vo *vo) { caca_event_t cev; while (caca_get_event(display, CACA_EVENT_ANY, &cev, 0)) { switch (cev.type) { case CACA_EVENT_RESIZE: caca_refresh_display(display); resize(); break; case CACA_EVENT_QUIT: mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN); break; case CACA_EVENT_MOUSE_MOTION: vo_mouse_movement(vo, cev.data.mouse.x, cev.data.mouse.y); break; case CACA_EVENT_MOUSE_PRESS: if (!vo->opts->nomouse_input) mp_input_put_key(vo->input_ctx, (MP_MOUSE_BTN0 + cev.data.mouse.button - 1) | MP_KEY_STATE_DOWN); break; case CACA_EVENT_MOUSE_RELEASE: if (!vo->opts->nomouse_input) mp_input_put_key(vo->input_ctx, (MP_MOUSE_BTN0 + cev.data.mouse.button - 1) | MP_KEY_STATE_UP); break; case CACA_EVENT_KEY_PRESS: { int key = cev.data.key.ch; int mpkey = lookup_keymap_table(keysym_map, key); const char *msg_name; if (mpkey) mp_input_put_key(vo->input_ctx, mpkey); else switch (key) { case 'd': case 'D': /* Toggle dithering algorithm */ set_next_str(caca_get_dither_algorithm_list(dither), &dither_algo, &msg_name); caca_set_dither_algorithm(dither, dither_algo); break; case 'a': case 'A': /* Toggle antialiasing method */ set_next_str(caca_get_dither_antialias_list(dither), &dither_antialias, &msg_name); caca_set_dither_antialias(dither, dither_antialias); break; case 'h': case 'H': /* Toggle charset method */ set_next_str(caca_get_dither_charset_list(dither), &dither_charset, &msg_name); caca_set_dither_charset(dither, dither_charset); break; case 'c': case 'C': /* Toggle color method */ set_next_str(caca_get_dither_color_list(dither), &dither_color, &msg_name); caca_set_dither_color(dither, dither_color); break; default: if (key <= 255) mp_input_put_key(vo->input_ctx, key); break; } } } } }