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; 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_msg(MSGT_VO, MSGL_V, "[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_msg(MSGT_VO, MSGL_V, "[vo] resize window: %d:%d\n", vo->dwidth, vo->dheight); break; } case WM_SIZING: if (vo->opts->keepaspect && !vo->opts->fs && 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 = vo->aspdat.asp; 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: mplayer_put_key(vo->key_fifo, MP_KEY_CLOSE_WIN); break; case WM_SYSCOMMAND: switch (wParam) { case SC_SCREENSAVE: case SC_MONITORPOWER: mp_msg(MSGT_VO, MSGL_V, "vo: win32: killing screensaver\n"); return 0; } break; case WM_KEYDOWN: case WM_SYSKEYDOWN: { int mpkey = lookup_keymap_table(vk_map, wParam); if (mpkey) mplayer_put_key(vo->key_fifo, 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)) 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)) { mplayer_put_key(vo->key_fifo, code | mods); // At least with Alt+char, not calling DefWindowProcW stops // Windows from emitting a beep. return 0; } break; } case WM_LBUTTONDOWN: if (!vo->opts->nomouse_input && (vo->opts->fs || (wParam & MK_CONTROL))) { mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN0 | mod_state(vo)); break; } if (!vo->opts->fs) { ReleaseCapture(); SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); return 0; } break; case WM_MBUTTONDOWN: if (!vo->opts->nomouse_input) mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN1 | mod_state(vo)); break; case WM_RBUTTONDOWN: if (!vo->opts->nomouse_input) mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN2 | mod_state(vo)); break; case WM_MOUSEMOVE: vo_mouse_movement(vo, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_MOUSEWHEEL: if (!vo->opts->nomouse_input) { int x = GET_WHEEL_DELTA_WPARAM(wParam); if (x > 0) mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN3 | mod_state(vo)); else mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN4 | mod_state(vo)); } break; case WM_XBUTTONDOWN: if (!vo->opts->nomouse_input) { int x = HIWORD(wParam); if (x == 1) mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN5 | mod_state(vo)); else // if (x == 2) mplayer_put_key(vo->key_fifo, MP_MOUSE_BTN6 | mod_state(vo)); } break; } return DefWindowProcW(hWnd, message, wParam, lParam); }
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); }