📄 gui_w32.c
字号:
/*
* Get a message when the user switches back to vim
*/
static void
_OnActivateApp(
HWND hwnd,
BOOL fActivate,
DWORD dwThreadId)
{
/* When activated: Check if any file was modified outside of Vim. */
if (fActivate)
check_timestamps();
}
/*
* Get a message when the the window is being destroyed.
*/
static void
_OnDestroy(
HWND hwnd)
{
if (!destroying)
_OnClose(hwnd);
}
static void
_OnDropFiles(
HWND hwnd,
HDROP hDrop)
{
char szFile[_MAX_PATH];
UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, szFile, _MAX_PATH);
UINT i;
char_u *fname;
char_u **fnames;
char_u redo_dirs = FALSE;
/* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
/* reset_VIsual(); */
if (VIsual_active)
{
end_visual_mode();
VIsual_reselect = FALSE;
update_curbuf(NOT_VALID); /* delete the inversion */
}
fnames = (char_u **) alloc(cFiles * sizeof(char_u *));
for (i = 0; i < cFiles; ++i)
{
DragQueryFile(hDrop, i, szFile, _MAX_PATH);
/* TRACE(" dropped %2u: '%s'\n", i, szFile); */
mch_dirname(IObuff, IOSIZE);
fname = shorten_fname(szFile, IObuff);
if (fname == NULL)
fname = szFile;
fnames[i] = vim_strsave(fname);
}
/*
* Handle dropping a directory on Vim.
*/
if (cFiles == 1)
{
if (mch_isdir(fnames[0]))
{
if (mch_chdir(fnames[0]) == 0)
{
vim_free(fnames[0]);
fnames[0] = NULL;
redo_dirs = TRUE;
}
}
}
DragFinish(hDrop);
if (GetKeyState(VK_SHIFT) & 0x8000)
{
/* Shift held down, change to first file's directory */
if (vim_chdirfile(fnames[0]) == 0)
{
redo_dirs = TRUE;
}
}
/* Handle the drop, by resetting the :args list */
handle_drop(cFiles, fnames);
if (redo_dirs)
shorten_fnames();
/* Update the screen display */
update_screen(NOT_VALID);
setcursor();
out_flush();
}
static void
_OnDeadChar(
HWND hwnd,
UINT ch,
int cRepeat)
{
dead_key = 1;
}
static void
_OnChar(
HWND hwnd,
UINT ch,
int cRepeat)
{
char_u string[1];
/* TRACE("OnChar(%d, %c)\n", ch, ch); */
string[0] = ch;
if (string[0] == Ctrl('C') && !mapped_ctrl_c)
{
trash_input_buf();
got_int = TRUE;
}
add_to_input_buf(string, 1);
}
static void
_OnSysChar(
HWND hwnd,
UINT ch,
int cRepeat)
{
char_u string[6]; /* Enough for maximum key sequence - see below */
int len;
int modifiers;
/* TRACE("OnSysChar(%d, %c)\n", ch, ch); */
/* OK, we have a character key (given by ch) which was entered with the
* ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
* that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
* CAPSLOCK is pressed) at this point.
*/
modifiers = MOD_MASK_ALT;
if (GetKeyState(VK_SHIFT) & 0x8000)
modifiers |= MOD_MASK_SHIFT;
if (GetKeyState(VK_CONTROL) & 0x8000)
modifiers |= MOD_MASK_CTRL;
ch = simplify_key(ch, &modifiers);
/* remove the SHIFT modifier for keys where it's already included, e.g.,
* '(' and '*' */
if (ch < 0x100 && (!isalpha(ch)) && isprint(ch))
modifiers &= ~MOD_MASK_SHIFT;
/* Interpret the ALT key as making the key META */
if (modifiers & MOD_MASK_ALT)
{
ch |= 0x80;
modifiers &= ~MOD_MASK_ALT;
}
len = 0;
if (modifiers)
{
string[len++] = CSI;
string[len++] = KS_MODIFIER;
string[len++] = modifiers;
}
if (IS_SPECIAL(ch))
{
string[len++] = CSI;
string[len++] = K_SECOND(ch);
string[len++] = K_THIRD(ch);
}
else
string[len++] = ch;
add_to_input_buf(string, len);
}
static void
_OnMouseEvent(
int button,
int x,
int y,
int repeated_click,
UINT keyFlags)
{
int vim_modifiers = 0x0;
if (keyFlags & MK_SHIFT)
vim_modifiers |= MOUSE_SHIFT;
if (keyFlags & MK_CONTROL)
vim_modifiers |= MOUSE_CTRL;
if (GetKeyState(VK_MENU) & 0x8000)
vim_modifiers |= MOUSE_ALT;
gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
}
static void
_OnMouseButtonDown(
HWND hwnd,
BOOL fDoubleClick,
int x,
int y,
UINT keyFlags)
{
static LONG s_prevTime = 0;
LONG currentTime = GetMessageTime();
int button = -1;
int repeated_click;
if (s_uMsg == WM_LBUTTONDOWN || s_uMsg == WM_LBUTTONDBLCLK)
button = MOUSE_LEFT;
else if (s_uMsg == WM_MBUTTONDOWN || s_uMsg == WM_MBUTTONDBLCLK)
button = MOUSE_MIDDLE;
else if (s_uMsg == WM_RBUTTONDOWN || s_uMsg == WM_RBUTTONDBLCLK)
button = MOUSE_RIGHT;
else if (s_uMsg == WM_CAPTURECHANGED)
{
/* on W95/NT4, somehow you get in here with an odd Msg
* if you press one button while holding down the other..*/
if (s_button_pending == MOUSE_LEFT)
button = MOUSE_RIGHT;
else
button = MOUSE_LEFT;
}
if (button >= 0)
{
repeated_click = ((int)(currentTime - s_prevTime) < p_mouset);
/*
* Holding down the left and right buttons simulates pushing the middle
* button.
*/
if (repeated_click &&
((button == MOUSE_LEFT && s_button_pending == MOUSE_RIGHT) ||
(button == MOUSE_RIGHT && s_button_pending == MOUSE_LEFT)))
{
/*
* Hmm, gui.c will ignore more than one button down at a time, so
* pretend we let go of it first.
*/
gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, 0x0);
button = MOUSE_MIDDLE;
repeated_click = FALSE;
s_button_pending = -1;
_OnMouseEvent(button, x, y, repeated_click, keyFlags);
}
else if ((repeated_click)
|| (mouse_model_popup() && (button == MOUSE_RIGHT)))
{
if (s_button_pending > -1)
{
_OnMouseEvent(s_button_pending, x, y, FALSE, keyFlags);
s_button_pending = -1;
}
/* TRACE("Button down at x %d, y %d\n", x, y); */
_OnMouseEvent(button, x, y, repeated_click, keyFlags);
}
else
{
/*
* If this is the first press (i.e. not a multiple click) don't
* action immediately, but store and wait for:
* i) button-up
* ii) mouse move
* iii) another button press
* before using it.
* This enables us to make left+right simulate middle button,
* without left or right being actioned first. The side-effect is
* that if you click and hold the mouse without dragging, the
* cursor doesn't move until you release the button. In practice
* this is hardly a problem.
*/
s_button_pending = button;
s_x_pending = x;
s_y_pending = y;
s_kFlags_pending = keyFlags;
}
s_prevTime = currentTime;
}
}
static void
_OnMouseMoveOrRelease(
HWND hwnd,
int x,
int y,
UINT keyFlags)
{
int button;
if (s_button_pending > -1)
{
/* Delayed action for mouse down event */
_OnMouseEvent(s_button_pending, s_x_pending,
s_y_pending, FALSE, s_kFlags_pending);
s_button_pending = -1;
}
if (s_uMsg == WM_MOUSEMOVE)
{
/*
* It's only a MOUSE_DRAG if one or more mouse buttons are being held
* down.
*/
if (!(keyFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)))
{
gui_mouse_moved(y);
return;
}
/*
* While button is down, keep grabbing mouse move events when
* the mouse goes outside the window
*/
SetCapture(s_textArea);
button = MOUSE_DRAG;
/* TRACE(" move at x %d, y %d\n", x, y); */
}
else
{
ReleaseCapture();
button = MOUSE_RELEASE;
/* TRACE(" up at x %d, y %d\n", x, y); */
}
_OnMouseEvent(button, x, y, FALSE, keyFlags);
}
static void
_OnPaint(
HWND hwnd)
{
if (!IsMinimized(hwnd))
{
PAINTSTRUCT ps;
HDC hdc;
out_flush(); /* make sure all output has been processed */
hdc = BeginPaint(hwnd, &ps);
#ifdef MULTI_BYTE
/* prevent multi-byte characters from misprinting on an invalid
* rectangle */
if (is_dbcs)
{
RECT rect;
GetClientRect(hwnd, &rect);
ps.rcPaint.left = rect.left;
ps.rcPaint.right = rect.right;
}
#endif
if (!IsRectEmpty(&ps.rcPaint))
gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left + 1,
ps.rcPaint.bottom - ps.rcPaint.top + 1);
EndPaint(hwnd, &ps);
}
}
static void
_OnSize(
HWND hwnd,
UINT state,
int cx,
int cy)
{
if (!IsMinimized(hwnd))
{
gui_resize_window(cx, cy);
/* Menu bar may wrap differently now */
gui_w32_get_menu_height(TRUE);
}
}
static void
_OnSetFocus(
HWND hwnd,
HWND hwndOldFocus)
{
gui_focus_change(TRUE);
}
static void
_OnKillFocus(
HWND hwnd,
HWND hwndNewFocus)
{
gui_focus_change(FALSE);
}
/*
* Find the GuiMenu with the given id
*/
static GuiMenu *
gui_w32_find_menu(
GuiMenu *pMenu,
int id)
{
GuiMenu *pChildMenu;
while (pMenu)
{
if (pMenu->id == (UINT)id) /* && pMenu->submenu_id == NULL) */
break;
if (pMenu->children != NULL)
{
pChildMenu = gui_w32_find_menu(pMenu->children, id);
if (pChildMenu)
{
pMenu = pChildMenu;
break;
}
}
pMenu = pMenu->next;
}
return pMenu;
}
static void
_OnMenu(
HWND hwnd,
int id,
HWND hwndCtl,
UINT codeNotify)
{
GuiMenu *pMenu;
pMenu = gui_w32_find_menu(gui.root_menu, id);
if (pMenu)
gui_menu_cb(pMenu);
}
/*
* Find the scrollbar with the given hwnd.
*/
static GuiScrollbar *
gui_w32_find_scrollbar(HWND hwnd)
{
WIN *wp;
if (gui.bottom_sbar.id == hwnd)
return &gui.bottom_sbar;
for (wp = firstwin; wp != NULL; wp = wp->w_next)
{
if (wp->w_scrollbars[SBAR_LEFT].id == hwnd)
return &wp->w_scrollbars[SBAR_LEFT];
if (wp->w_scrollbars[SBAR_RIGHT].id == hwnd)
return &wp->w_scrollbars[SBAR_RIGHT];
}
return NULL;
}
static int
_OnScroll(
HWND hwnd,
HWND hwndCtl,
UINT code,
int pos)
{
GuiScrollbar *sb, *sb_info;
int val;
int dragging = FALSE;
SCROLLINFO si;
WIN *wp;
sb = gui_w32_find_scrollbar(hwndCtl);
if (sb == NULL)
return 0;
if (sb->wp != NULL) /* Left or right scrollbar */
{
/*
* Careful: need to get scrollbar info out of first (left) scrollbar
* for window, but keep real scrollbar too because we must pass it to
* gui_drag_scrollbar().
*/
sb_info = &sb->wp->w_scrollbars[0];
}
else /* Bottom scrollbar */
sb_info = sb;
val = sb_info->value;
switch (code)
{
case SB_THUMBTRACK:
/* TRACE("SB_THUMBTRACK, %d\n", pos); */
val = pos;
dragging = TRUE;
if (scroll_shift > 0)
val <<= scroll_shift;
break;
case SB_LINEDOWN:
/* TRACE("SB_LINEDOWN\n"); */
val++;
break;
case SB_LINEUP:
/* TRACE("SB_LINEUP\n"); */
val--;
break;
case SB_PAGEDOWN:
/* TRACE("SB_PAGEDOWN\n"); */
val += (sb_info->size > 2 ? sb_info->size - 2 : 1);
break;
case SB_PAGEUP:
/* TRACE("SB_PAGEUP\n"); */
val -= (sb_info->size > 2 ? sb_info->size - 2 : 1);
break;
case SB_TOP:
/* TRACE("SB_TOP\n"); */
val = 0;
break;
case SB_BOTTOM:
/* TRACE("SB_BOTTOM\n"); */
val = sb_info->max;
break;
case SB_ENDSCROLL:
/*
* "pos" only gives us 16-bit data. In case of large file, use
* GetScrollPos() which returns 32-bit. Unfortunately it is not
* valid while the scrollbar is being dragged.
*/
/* TRACE("SB_ENDSCROLL\n"); */
val = GetScrollPos(hwndCtl, SB_CTL);
if (scroll_shift > 0)
val <<= scroll_shift;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -