Exemplo n.º 1
0
/*
 * FUNCTION
 *   mousemove(int    *sel_pending,
 *             POINT  *first,
 *             POINT  *current,
 *             MARK   *lmbdn_mark,
 *             int    rect_rgn)
 *
 *   sel_pending - Boolean, T -> client has recorded a left mouse button (LMB)
 *                 click, and so, a selection is pending.
 *
 *   first       - editor row/col coordinates where LMB was initially recorded.
 *
 *   latest      - during the mouse move, assuming the LMB is still down,
 *                 "latest" tracks the cursor position wrt window resizing
 *                 operations (via a modeline drag).
 *
 *   current     - current cursor row/col coordiantes.
 *
 *   lmbdn_mark  - editor MARK when "LMB down" was initially recorded.
 *
 *   rect_rgn    - Boolean, T -> user wants rectangular region selection.
 *
 * DESCRIPTION
 *   Using several state variables, this function handles all the semantics
 *   of a left mouse button "MOVE" event.  The semantics are as follows:
 *
 *   1) This function will not be called unless the LMB is down and the
 *      cursor is not being used to drage the mode line (enforced by caller).
 *   2) a LMB move within the current editor window selects a region of text.
 *      Later, when the user releases the LMB, that text is yanked to the
 *      unnamed register (the yank code is not handled in this function).
 *
 * RETURNS
 *   None
 */
static void
mousemove(int *sel_pending,
	  COORD * first,
	  COORD * current,
	  MARK *lmbdn_mark,
	  int rect_rgn)
{
    int dummy;

    if (WaitForSingleObject(hAsMutex, AS_TMOUT) == WAIT_OBJECT_0) {
	if (*sel_pending) {
	    /*
	     * Selection pending.  If the mouse has moved at least one char,
	     * start a selection.
	     */

	    if (MouseClickSetPos(current, &dummy)) {
		/* ignore mouse jitter */

		if (current->X != first->X || current->Y != first->Y) {
		    *sel_pending = FALSE;
		    DOT = *lmbdn_mark;
		    (void) sel_begin();
		    (void) update(TRUE);
		} else {
		    (void) ReleaseMutex(hAsMutex);
		    return;
		}
	    }
	}
	if (mouse_wp != row2window(current->Y)) {
	    /*
	     * mouse moved into a different editor window or row2window()
	     * returned a NULL ptr.
	     */

	    (void) ReleaseMutex(hAsMutex);
	    return;
	}
	if (!setcursor(current->Y, current->X)) {
	    (void) ReleaseMutex(hAsMutex);
	    return;
	}
	if (rect_rgn)
	    (void) sel_setshape(rgn_RECTANGLE);
	if (sel_extend(TRUE, TRUE))
	    (void) update(TRUE);
	(void) ReleaseMutex(hAsMutex);
    }
    /*
     * Else either the worker thread abandonded the mutex (not possible as
     * currently coded) or timed out.  If the latter, something is
     * hung--don't do anything.
     */
}
Exemplo n.º 2
0
static int
MouseClickSetPos(COORD * result, int *onmode)
{
    WINDOW *wp;

    TRACE(("GETC:setcursor(%d, %d)\n", result->Y, result->X));

    /*
     * If we're getting a button-down in a window, allow it to begin a
     * selection.  A button-down on its modeline will allow resizing the
     * window.
     */
    *onmode = FALSE;
    if ((wp = row2window(result->Y)) != 0) {
	if (result->Y == mode_row(wp)) {
	    *onmode = TRUE;
	    return TRUE;
	}
	return setcursor(result->Y, result->X);
    }
    return FALSE;
}
Exemplo n.º 3
0
static int
xterm_button(int c)
{
	WINDOW	*wp;
	int	event;
	int	button;
	int	x;
	int	y;
	int	status;
#if OPT_XTERM >= 3
	int	save_row = ttrow;
	int	save_col = ttcol;
	int	firstrow, lastrow;
	int	startx, endx, mousex;
	int	starty, endy, mousey;
	MARK	save_dot;
	char	temp[NSTRING];
	static	const	char	*fmt = "\033[%d;%d;%d;%d;%dT";
#endif	/* OPT_XTERM >= 3 */

	if (insertmode)
		return ABORT;

	if ((status = (global_g_val(GMDXTERM_MOUSE))) != 0) {
		beginDisplay;
		switch(c) {
		case 'M':	/* button-event */
			event	= keystroke();
			x	= XtermPos() + x_origin;
			y	= XtermPos() + y_origin;

			button	= (event & 3) + 1;
			TRACE(("M-button event:%d x:%d y:%d\n", event, x, y))
			if (button > 3) {
				endofDisplay;
				return TRUE; /* button up */
			}
			wp = row2window(y-1);
#if OPT_XTERM >= 3
			/* Tell the xterm how to highlight the selection.
			 * It won't do anything else until we do this.
			 */
			if (wp != 0) {
				firstrow = wp->w_toprow + 1;
				lastrow  = mode_row(wp) + 1;
			} else {		/* from message-line */
				firstrow = term.t_nrow ;
				lastrow  = term.t_nrow + 1;
			}
			if (y >= lastrow)	/* don't select modeline */
				y = lastrow - 1;
			(void)lsprintf(temp, fmt, 1, x, y, firstrow, lastrow);
			putpad(temp);
			TTflush();
#endif	/* OPT_XTERM >= 3 */
			/* Set the dot-location if button 1 was pressed in a
			 * window.
			 */
			if (wp != 0
			 && button == 1
			 && !reading_msg_line
			 && setcursor(y-1, x-1)) {
				/*mlerase();*/
				(void)update(TRUE);
				status = TRUE;
			} else if (button <= 3) {
#if OPT_XTERM >= 3
				/* abort the selection */
				(void)lsprintf(temp, fmt, 0, x, y, firstrow, lastrow);
				putpad(temp);
				TTflush();
#endif	/* OPT_XTERM >= 3 */
				status = ABORT;
			} else {
				status = FALSE;
			}
			break;
#if OPT_XTERM >= 3
		case 't':	/* reports valid text-location */
			x = XtermPos();
			y = XtermPos();

			TRACE(("t: x:%d y:%d\n", x, y))
			setwmark(y-1, x-1);
			yankregion();

			movecursor(save_row, save_col);
			/*mlerase();*/
			(void)update(TRUE);
			break;
		case 'T':	/* reports invalid text-location */
			/*
			 * The starting-location returned is not the location
			 * at which the mouse was pressed.  Instead, it is the
			 * top-most location of the selection.  In turn, the
			 * ending-location is the bottom-most location of the
			 * selection.  The mouse-up location is not necessarily
			 * a pointer to valid text.
			 *
			 * This case handles multi-clicking events as well as
			 * selections whose start or end location was not
			 * pointing to text.
			 */
			save_dot = DOT;
			startx = XtermPos();	/* starting-location */
			starty = XtermPos();
			endx   = XtermPos();	/* ending-location */
			endy   = XtermPos();
			mousex = XtermPos();	/* location at mouse-up */
			mousey = XtermPos();

			TRACE(("T: start(%d,%d) end(%d,%d) mouse(%d,%d)\n",
				starty, startx,
				endy,   endx,
				mousey, mousex))
			setcursor(starty - 1, startx - 1);
			setwmark (endy   - 1, endx   - 1);
			if (MK.o != 0 && !is_at_end_of_line(MK))
				MK.o += 1;
			yankregion();

			DOT = save_dot;
			movecursor(save_row, save_col);
			/*mlerase();*/
			(void)update(TRUE);
			break;
#endif /* OPT_XTERM >= 3 */
		default:
			status = FALSE;
		}
		endofDisplay;
	}
Exemplo n.º 4
0
static void
handle_mouse_event(MOUSE_EVENT_RECORD mer)
{
    static DWORD lastclick = 0;
    static int clicks = 0;

    int onmode = FALSE;
    COORD current, first, latest;
    MARK lmbdn_mark;		/* left mouse button down here */
    int sel_pending = 0, state;
    DWORD thisclick;
    UINT clicktime = GetDoubleClickTime();

    buttondown = FALSE;
    for_ever {
	current = mer.dwMousePosition;
	switch (mer.dwEventFlags) {
	case 0:
	    state = mer.dwButtonState;
	    if (state == 0) {	/* button released */
		thisclick = GetTickCount();
		TRACE(("CLICK %d/%d\n", lastclick, thisclick));
		if (thisclick - lastclick < clicktime) {
		    clicks++;
		    TRACE(("MOUSE CLICKS %d\n", clicks));
		} else {
		    clicks = 0;
		}
		lastclick = thisclick;

		switch (clicks) {
		case 1:
		    on_double_click();
		    break;
		case 2:
		    on_triple_click();
		    break;
		}

		if (buttondown) {
		    int dummy;

		    halt_autoscroll_thread();

		    /* Finalize cursor position. */
		    (void) MouseClickSetPos(&current, &dummy);
		    if (!(onmode || sel_pending))
			sel_yank(0);
		}
		return;
	    }
	    if (state & FROM_LEFT_1ST_BUTTON_PRESSED) {
		if (MouseClickSetPos(&current, &onmode)) {
		    first = latest = current;
		    lmbdn_mark = DOT;
		    sel_pending = FALSE;
		    mouse_wp = row2window(latest.Y);
		    if (onmode) {
			buttondown = TRUE;
			sel_release();
			update(TRUE);
		    } else {
			HWND hwnd;

			(void) update(TRUE);	/* possible wdw change */
			buttondown = FALSE;	/* until all inits are successful */

			/* Capture mouse to console vile's window handle. */
			hwnd = GetVileWindow();
			(void) SetCapture(hwnd);

			/* Compute pixel height of each row on screen. */
			(void) GetClientRect(hwnd, &client_rect);
			row_height = client_rect.bottom / term.rows;

			/*
			 * Create mutex to ensure that main thread and worker
			 * thread don't update display at the same time.
			 */
			if ((hAsMutex = CreateMutex(0, FALSE, 0)) == NULL)
			    mlforce("[Can't create autoscroll mutex]");
			else {
			    /*
			     * Setup a worker thread to act as a pseudo
			     * timer that kicks off autoscroll when
			     * necessary.
			     */

			    if (_beginthread(autoscroll_thread,
					     0,
					     NULL) == (unsigned long) -1) {
				(void) CloseHandle(hAsMutex);
				mlforce("[Can't create autoscroll thread]");
			    } else
				sel_pending = buttondown = TRUE;
			}
			if (!buttondown)
			    (void) ReleaseCapture();
		    }
		}
	    } else if (state & FROM_LEFT_2ND_BUTTON_PRESSED) {
		if (MouseClickSetPos(&current, &onmode)
		    && !onmode) {
		    sel_yank(0);
		    sel_release();
		    paste_selection();
		    (void) update(TRUE);
		}
		return;
	    } else {
		if (MouseClickSetPos(&current, &onmode)
		    && onmode) {
		    sel_release();
		    update(TRUE);
		} else {
		    kbd_alarm();
		}
	    }
	    break;

	case MOUSE_MOVED:
	    if (!buttondown)
		return;
	    if (onmode) {
		/* on mode line, resize window (if possible). */

		if (!adjust_window(mouse_wp, &current, &latest)) {
		    /*
		     * left mouse button still down, but cursor moved off mode
		     * line.  Update latest to keep track of cursor in case
		     * it wanders back on the mode line.
		     */

		    latest = current;
		}
	    } else {
		mousemove(&sel_pending,
			  &first,
			  &current,
			  &lmbdn_mark,
			  (mer.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
		    );
	    }
	    break;

#ifdef MOUSE_WHEELED
	case MOUSE_WHEELED:
	    /*
	     * Trial and error experimentation shows that dwButtonState
	     * has its high bit set when the wheel moves back and not
	     * set otherwise.
	     */
	    mvupwind(TRUE, ((long) mer.dwButtonState < 0) ? -3 : 3);
	    update(TRUE);
	    return;
#endif /* MOUSE_WHEELED */
	}

	for_ever {
	    INPUT_RECORD ir;
	    DWORD nr;
	    int key;

	    if (!ReadConsoleInput(hConsoleInput, &ir, 1, &nr))
		imdying(0);
	    switch (ir.EventType) {
	    case KEY_EVENT:
		key = decode_key_event(&ir);
		if (key == ESC) {
		    if (buttondown)
			halt_autoscroll_thread();
		    sel_release();
		    (void) update(TRUE);
		    return;
		}
		continue;

	    case MOUSE_EVENT:
		mer = ir.Event.MouseEvent;
		break;
	    }
	    break;
	}
    }
}
Exemplo n.º 5
0
/*
 * On button press, we get an explicit number (1,2,3), and on release we don't
 * really know which button, but assume it is the last-pressed button.
 */
int
on_mouse_click(int button, int y, int x)
{
    static int first_x, first_y, pending;
    WINDOW *this_wp, *that_wp;
    int status;

    if (button > 0) {
	if (valid_window(this_wp = row2window(y))
	    && (y != mode_row(this_wp))) {
	    /*
	     * If we get a click on the "<" marking the left side
	     * of a shifted window, force the screen right. This
	     * makes it more consistent if there's a tab.
	     */
	    if (w_val(this_wp, WVAL_SIDEWAYS)
		&& x == 0) {
		mvleftwind(FALSE, 1);
	    }
	    if (!doingsweep) {
		if (button == BTN_EXTEND) {
		    first_x = offs2col(this_wp, this_wp->w_dot.l, this_wp->w_dot.o);
		    first_y = line_no(this_wp->w_bufp, this_wp->w_dot.l)
			- line_no(this_wp->w_bufp, this_wp->w_line.l);
		} else {
		    first_x = x;
		    first_y = y;
		}
	    }
	    status = setcursor(y, x);
	    /*
	     * Check for button1-down while we're in multimotion
	     * sweep, so we can suppress highlighting extension.
	     */
	    if (button != BTN_EXTEND
		&& status == TRUE
		&& doingsweep) {
		status = SORTOFTRUE;
		if (button == BTN_BEGIN) {
		    first_x = x;
		    first_y = y;
		}
	    }
	} else {		/* pressed button on modeline */
	    status = SORTOFTRUE;
	    first_x = x;
	    first_y = y;
	}
	pending = button;
    } else if (pending) {
	button = pending;
	pending = FALSE;
	this_wp = row2window(y);
	that_wp = row2window(first_y);
	if (this_wp == 0
	    || that_wp == 0
	    || reading_msg_line) {
	    TRACE(("MOUSE cannot move msg-line\n"));
	    status = FALSE;
	} else if (insertmode
		   && (this_wp != curwp || that_wp != curwp)) {
	    TRACE(("MOUSE cannot move from window while inserting\n"));
	    kbd_alarm();
	    status = ABORT;
	} else if (first_y == mode_row(that_wp)) {	/* drag modeline? */
	    if (first_y == y) {
		sel_release();
		status = SEL_RELEASE;
	    } else {
		WINDOW *save_wp = curwp;
		TRACE(("MOUSE dragging modeline\n"));
		set_curwp(that_wp);
		status = shrinkwind(FALSE, first_y - y);
		set_curwp(save_wp);
	    }
	} else if (y != first_y || x != first_x) {	/* drag selection */
	    if (button == BTN_PASTE) {
		(void) setcursor(y, x);
		status = paste_selection();
	    } else if (doingsweep) {
		switch (button) {
		case BTN_BEGIN:
		    (void) release_selection(TRUE);
		    status = setcursor(first_y, first_x);
		    if (status == TRUE) {
			MK = DOT;
			status = SEL_BEGIN;
			TRACE(("MOUSE setting SEL_BEGIN MK %d.%d\n",
			       line_no(curbp, MK.l), MK.o));
		    }
		    break;
		default:
		    (void) setcursor(y, x);
		    status = SEL_EXTEND;
		    TRACE(("MOUSE setting SEL_EXTEND DOT %d.%d MK %d.%d\n",
			   line_no(curbp, MK.l), MK.o,
			   line_no(curbp, DOT.l), DOT.o));
		    break;
		}
	    } else {
		TRACE(("MOUSE begin multimotion on button%d-up\n", button));
		if (button == BTN_EXTEND) {
		    (void) setcursor(y, x);
		    y = first_y;
		    x = first_x;
		}
		do_sweep(SORTOFTRUE);
		(void) sel_begin();
		(void) sel_setshape(rgn_EXACT);
		(void) setcursor(y, x);
		status = multimotion(TRUE, 1);
		TRACE(("MOUSE end multimotion after button%d-up\n", button));
		if (status == SEL_PASTE)
		    status = paste_selection();
	    }
	} else {		/* position the cursor */
	    TRACE(("MOUSE button %d position cursor\n", button));
	    (void) setcursor(y, x);
	    switch (button) {
	    case BTN_BEGIN:
		status = SEL_FINISH;
		break;
	    case BTN_PASTE:
		status = paste_selection();
		break;
	    default:
		status = release_selection(TRUE);
		break;
	    }
	}
    } else {
	TRACE(("MOUSE ignored (illegal state)\n"));
	status = FALSE;
    }

    if (status == TRUE || status >= SORTOFTRUE)
	(void) update(TRUE);

    TRACE(("MOUSE status:%d\n", status));
    return status;
}