533 lines
12 KiB
C
533 lines
12 KiB
C
/*
|
||
* tkWinPointer.c --
|
||
*
|
||
* Windows specific mouse tracking code.
|
||
*
|
||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||
* Copyright (c) 1998-1999 by Scriptics Corporation.
|
||
*
|
||
* See the file "license.terms" for information on usage and redistribution of
|
||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
*/
|
||
|
||
#include "tkWinInt.h"
|
||
|
||
/*
|
||
* Check for enter/leave events every MOUSE_TIMER_INTERVAL milliseconds.
|
||
*/
|
||
|
||
#define MOUSE_TIMER_INTERVAL 250
|
||
|
||
/*
|
||
* Declarations of static variables used in this file.
|
||
*/
|
||
|
||
static int captured = 0; /* 1 if mouse is currently captured. */
|
||
static TkWindow *keyboardWinPtr = NULL; /* Current keyboard grab window. */
|
||
static Tcl_TimerToken mouseTimer; /* Handle to the latest mouse timer. */
|
||
static int mouseTimerSet = 0; /* 1 if the mouse timer is active. */
|
||
|
||
/*
|
||
* Forward declarations of procedures used in this file.
|
||
*/
|
||
|
||
static void MouseTimerProc(ClientData clientData);
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkWinGetModifierState --
|
||
*
|
||
* Return the modifier state as of the last message.
|
||
*
|
||
* Results:
|
||
* Returns the X modifier mask.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
TkWinGetModifierState(void)
|
||
{
|
||
int state = 0;
|
||
|
||
if (GetKeyState(VK_SHIFT) & 0x8000) {
|
||
state |= ShiftMask;
|
||
}
|
||
if (GetKeyState(VK_CONTROL) & 0x8000) {
|
||
state |= ControlMask;
|
||
}
|
||
if (GetKeyState(VK_MENU) & 0x8000) {
|
||
state |= ALT_MASK;
|
||
}
|
||
if (GetKeyState(VK_CAPITAL) & 0x0001) {
|
||
state |= LockMask;
|
||
}
|
||
if (GetKeyState(VK_NUMLOCK) & 0x0001) {
|
||
state |= Mod1Mask;
|
||
}
|
||
if (GetKeyState(VK_SCROLL) & 0x0001) {
|
||
state |= Mod3Mask;
|
||
}
|
||
if (GetKeyState(VK_LBUTTON) & 0x8000) {
|
||
state |= Button1Mask;
|
||
}
|
||
if (GetKeyState(VK_MBUTTON) & 0x8000) {
|
||
state |= Button2Mask;
|
||
}
|
||
if (GetKeyState(VK_RBUTTON) & 0x8000) {
|
||
state |= Button3Mask;
|
||
}
|
||
return state;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* Tk_PointerEvent --
|
||
*
|
||
* This procedure is called for each pointer-related event. It converts
|
||
* the position to root coords and updates the global pointer state
|
||
* machine. It also ensures that the mouse timer is scheduled.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* May queue events and change the grab state.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
Tk_PointerEvent(
|
||
HWND hwnd, /* Window for coords, or NULL for the root
|
||
* window. */
|
||
int x, int y) /* Coords relative to hwnd, or screen if hwnd
|
||
* is NULL. */
|
||
{
|
||
POINT pos;
|
||
int state;
|
||
Tk_Window tkwin;
|
||
|
||
pos.x = x;
|
||
pos.y = y;
|
||
|
||
/*
|
||
* Convert client coords to root coords if we were given a window.
|
||
*/
|
||
|
||
if (hwnd) {
|
||
ClientToScreen(hwnd, &pos);
|
||
}
|
||
|
||
/*
|
||
* If the mouse is captured, Windows will report all pointer events to the
|
||
* capture window. So, we need to determine which window the mouse is
|
||
* really over and change the event. Note that the computed hwnd may point
|
||
* to a window not owned by Tk, or a toplevel decorative frame, so tkwin
|
||
* can be NULL.
|
||
*/
|
||
|
||
if (captured || hwnd == NULL) {
|
||
hwnd = WindowFromPoint(pos);
|
||
}
|
||
tkwin = Tk_HWNDToWindow(hwnd);
|
||
|
||
state = TkWinGetModifierState();
|
||
|
||
Tk_UpdatePointer(tkwin, pos.x, pos.y, state);
|
||
|
||
if ((captured || tkwin) && !mouseTimerSet) {
|
||
mouseTimerSet = 1;
|
||
mouseTimer = Tcl_CreateTimerHandler(MOUSE_TIMER_INTERVAL,
|
||
MouseTimerProc, NULL);
|
||
}
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XGrabKeyboard --
|
||
*
|
||
* Simulates a keyboard grab by setting the focus.
|
||
*
|
||
* Results:
|
||
* Always returns GrabSuccess.
|
||
*
|
||
* Side effects:
|
||
* Sets the keyboard focus to the specified window.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
XGrabKeyboard(
|
||
Display *display,
|
||
Window grab_window,
|
||
Bool owner_events,
|
||
int pointer_mode,
|
||
int keyboard_mode,
|
||
Time time)
|
||
{
|
||
keyboardWinPtr = TkWinGetWinPtr(grab_window);
|
||
return GrabSuccess;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XUngrabKeyboard --
|
||
*
|
||
* Releases the simulated keyboard grab.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Sets the keyboard focus back to the value before the grab.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
XUngrabKeyboard(
|
||
Display *display,
|
||
Time time)
|
||
{
|
||
keyboardWinPtr = NULL;
|
||
return Success;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* MouseTimerProc --
|
||
*
|
||
* Check the current mouse position and look for enter/leave events.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* May schedule a new timer and/or generate enter/leave events.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
MouseTimerProc(
|
||
ClientData clientData)
|
||
{
|
||
POINT pos;
|
||
|
||
mouseTimerSet = 0;
|
||
|
||
/*
|
||
* Get the current mouse position and window. Don't do anything if the
|
||
* mouse hasn't moved since the last time we looked.
|
||
*/
|
||
|
||
GetCursorPos(&pos);
|
||
Tk_PointerEvent(NULL, pos.x, pos.y);
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkWinCancelMouseTimer --
|
||
*
|
||
* If the mouse timer is set, cancel it.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* May cancel the mouse timer.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
TkWinCancelMouseTimer(void)
|
||
{
|
||
if (mouseTimerSet) {
|
||
Tcl_DeleteTimerHandler(mouseTimer);
|
||
mouseTimerSet = 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkGetPointerCoords --
|
||
*
|
||
* Fetch the position of the mouse pointer.
|
||
*
|
||
* Results:
|
||
* *xPtr and *yPtr are filled in with the root coordinates of the mouse
|
||
* pointer for the display.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
TkGetPointerCoords(
|
||
Tk_Window tkwin, /* Window that identifies screen on which
|
||
* lookup is to be done. */
|
||
int *xPtr, int *yPtr) /* Store pointer coordinates here. */
|
||
{
|
||
POINT point;
|
||
|
||
GetCursorPos(&point);
|
||
*xPtr = point.x;
|
||
*yPtr = point.y;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XQueryPointer --
|
||
*
|
||
* Check the current state of the mouse. This is not a complete
|
||
* implementation of this function. It only computes the root coordinates
|
||
* and the current mask.
|
||
*
|
||
* Results:
|
||
* Sets root_x_return, root_y_return, and mask_return. Returns true on
|
||
* success.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
Bool
|
||
XQueryPointer(
|
||
Display *display,
|
||
Window w,
|
||
Window *root_return,
|
||
Window *child_return,
|
||
int *root_x_return,
|
||
int *root_y_return,
|
||
int *win_x_return,
|
||
int *win_y_return,
|
||
unsigned int *mask_return)
|
||
{
|
||
display->request++;
|
||
TkGetPointerCoords(NULL, root_x_return, root_y_return);
|
||
*mask_return = TkWinGetModifierState();
|
||
return True;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XWarpPointer --
|
||
*
|
||
* Move pointer to new location. This is not a complete implementation of
|
||
* this function.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Mouse pointer changes position on screen.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
XWarpPointer(
|
||
Display *display,
|
||
Window src_w,
|
||
Window dest_w,
|
||
int src_x,
|
||
int src_y,
|
||
unsigned int src_width,
|
||
unsigned int src_height,
|
||
int dest_x,
|
||
int dest_y)
|
||
{
|
||
RECT r;
|
||
|
||
GetWindowRect(Tk_GetHWND(dest_w), &r);
|
||
SetCursorPos(r.left+dest_x, r.top+dest_y);
|
||
return Success;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XGetInputFocus --
|
||
*
|
||
* Retrieves the current keyboard focus window.
|
||
*
|
||
* Results:
|
||
* Returns the current focus window.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
XGetInputFocus(
|
||
Display *display,
|
||
Window *focus_return,
|
||
int *revert_to_return)
|
||
{
|
||
Tk_Window tkwin = Tk_HWNDToWindow(GetFocus());
|
||
|
||
*focus_return = tkwin ? Tk_WindowId(tkwin) : None;
|
||
*revert_to_return = RevertToParent;
|
||
display->request++;
|
||
return Success;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XSetInputFocus --
|
||
*
|
||
* Set the current focus window.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Changes the keyboard focus and causes the selected window to
|
||
* be activated.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
XSetInputFocus(
|
||
Display *display,
|
||
Window focus,
|
||
int revert_to,
|
||
Time time)
|
||
{
|
||
display->request++;
|
||
if (focus != None) {
|
||
SetFocus(Tk_GetHWND(focus));
|
||
}
|
||
return Success;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkpChangeFocus --
|
||
*
|
||
* This procedure is invoked to move the system focus from one window to
|
||
* another.
|
||
*
|
||
* Results:
|
||
* The return value is the serial number of the command that changed the
|
||
* focus. It may be needed by the caller to filter out focus change
|
||
* events that were queued before the command. If the procedure doesn't
|
||
* actually change the focus then it returns 0.
|
||
*
|
||
* Side effects:
|
||
* The official Windows focus window changes; the application's focus
|
||
* window isn't changed by this procedure.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
TkpChangeFocus(
|
||
TkWindow *winPtr, /* Window that is to receive the X focus. */
|
||
int force) /* Non-zero means claim the focus even if it
|
||
* didn't originally belong to topLevelPtr's
|
||
* application. */
|
||
{
|
||
TkDisplay *dispPtr = winPtr->dispPtr;
|
||
Window focusWindow;
|
||
int dummy, serial;
|
||
TkWindow *winPtr2;
|
||
|
||
if (!force) {
|
||
XGetInputFocus(dispPtr->display, &focusWindow, &dummy);
|
||
winPtr2 = (TkWindow *) Tk_IdToWindow(dispPtr->display, focusWindow);
|
||
if ((winPtr2 == NULL) || (winPtr2->mainPtr != winPtr->mainPtr)) {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
if (winPtr->window == None) {
|
||
Tcl_Panic("ChangeXFocus got null X window");
|
||
}
|
||
|
||
/*
|
||
* Change the foreground window so the focus window is raised to the top
|
||
* of the system stacking order and gets the keyboard focus.
|
||
*/
|
||
|
||
if (force) {
|
||
TkWinSetForegroundWindow(winPtr);
|
||
}
|
||
XSetInputFocus(dispPtr->display, winPtr->window, RevertToParent,
|
||
CurrentTime);
|
||
|
||
/*
|
||
* Remember the current serial number for the X server and issue a dummy
|
||
* server request. This marks the position at which we changed the focus,
|
||
* so we can distinguish FocusIn and FocusOut events on either side of the
|
||
* mark.
|
||
*/
|
||
|
||
serial = NextRequest(winPtr->display);
|
||
XNoOp(winPtr->display);
|
||
return serial;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkpSetCapture --
|
||
*
|
||
* This function captures the mouse so that all future events will be
|
||
* reported to this window, even if the mouse is outside the window. If
|
||
* the specified window is NULL, then the mouse is released.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Sets the capture flag and captures the mouse.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
TkpSetCapture(
|
||
TkWindow *winPtr) /* Capture window, or NULL. */
|
||
{
|
||
if (winPtr) {
|
||
SetCapture(Tk_GetHWND(Tk_WindowId(winPtr)));
|
||
captured = 1;
|
||
} else {
|
||
captured = 0;
|
||
ReleaseCapture();
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Local Variables:
|
||
* mode: c
|
||
* c-basic-offset: 4
|
||
* fill-column: 78
|
||
* End:
|
||
*/
|