1/*
2 *Copyright (C) 2004 Harold L Hunt II All Rights Reserved.
3 *
4 *Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 *"Software"), to deal in the Software without restriction, including
7 *without limitation the rights to use, copy, modify, merge, publish,
8 *distribute, sublicense, and/or sell copies of the Software, and to
9 *permit persons to whom the Software is furnished to do so, subject to
10 *the following conditions:
11 *
12 *The above copyright notice and this permission notice shall be
13 *included in all copies or substantial portions of the Software.
14 *
15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR
19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 *Except as contained in this notice, the name of Harold L Hunt II
24 *shall not be used in advertising or otherwise to promote the sale, use
25 *or other dealings in this Software without prior written authorization
26 *from Harold L Hunt II.
27 *
28 * Authors:	Harold L Hunt II
29 */
30
31#ifdef HAVE_XWIN_CONFIG_H
32#include <xwin-config.h>
33#endif
34#include "win.h"
35
36
37static HHOOK g_hhookKeyboardLL = NULL;
38
39
40/*
41 * Function prototypes
42 */
43
44static LRESULT CALLBACK
45winKeyboardMessageHookLL (int iCode, WPARAM wParam, LPARAM lParam);
46
47
48#ifndef LLKHF_EXTENDED
49# define LLKHF_EXTENDED  0x00000001
50#endif
51#ifndef LLKHF_UP
52# define LLKHF_UP  0x00000080
53#endif
54
55
56/*
57 * KeyboardMessageHook
58 */
59
60static LRESULT CALLBACK
61winKeyboardMessageHookLL (int iCode, WPARAM wParam, LPARAM lParam)
62{
63  BOOL			fPassKeystroke = FALSE;
64  BOOL			fPassAltTab = TRUE;
65  PKBDLLHOOKSTRUCT	p = (PKBDLLHOOKSTRUCT) lParam;
66  HWND			hwnd = GetActiveWindow();
67#ifdef XWIN_MULTIWINDOW
68  WindowPtr		pWin = NULL;
69  winPrivWinPtr	        pWinPriv = NULL;
70  winPrivScreenPtr	pScreenPriv = NULL;
71  winScreenInfo		*pScreenInfo = NULL;
72
73  /* Check if the Windows window property for our X window pointer is valid */
74  if ((pWin = GetProp (hwnd, WIN_WINDOW_PROP)) != NULL)
75    {
76      /* Get a pointer to our window privates */
77      pWinPriv		= winGetWindowPriv(pWin);
78
79      /* Get pointers to our screen privates and screen info */
80      pScreenPriv	= pWinPriv->pScreenPriv;
81      pScreenInfo	= pScreenPriv->pScreenInfo;
82
83      if (pScreenInfo->fMultiWindow)
84          fPassAltTab = FALSE;
85    }
86#endif
87
88  /* Pass keystrokes on to our main message loop */
89  if (iCode == HC_ACTION)
90    {
91      winDebug("winKeyboardMessageHook: vkCode: %08x scanCode: %08x\n", p->vkCode, p->scanCode);
92
93      switch (wParam)
94	{
95	case WM_KEYDOWN:  case WM_SYSKEYDOWN:
96	case WM_KEYUP:    case WM_SYSKEYUP:
97	  fPassKeystroke =
98	    (fPassAltTab &&
99                (p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0))
100	    || (p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)
101	    ;
102	  break;
103	}
104    }
105
106  /*
107   * Pass message on to our main message loop.
108   * We process this immediately with SendMessage so that the keystroke
109   * appears in, hopefully, the correct order.
110   */
111  if (fPassKeystroke)
112    {
113      LPARAM		lParamKey = 0x0;
114
115      /* Construct the lParam from KBDLLHOOKSTRUCT */
116      lParamKey = lParamKey | (0x0000FFFF & 0x00000001); /* Repeat count */
117      lParamKey = lParamKey | (0x00FF0000 & (p->scanCode << 16));
118      lParamKey = lParamKey
119	| (0x01000000 & ((p->flags & LLKHF_EXTENDED) << 23));
120      lParamKey = lParamKey
121	| (0x20000000
122	   & ((p->flags & LLKHF_ALTDOWN) << 24));
123      lParamKey = lParamKey | (0x80000000 & ((p->flags & LLKHF_UP) << 24));
124
125      /* Send message to our main window that has the keyboard focus */
126      PostMessage (hwnd,
127		   (UINT) wParam,
128		   (WPARAM) p->vkCode,
129		   lParamKey);
130
131      return 1;
132    }
133
134  /* Call next hook */
135  return CallNextHookEx (NULL, iCode, wParam, lParam);
136}
137
138
139/*
140 * Attempt to install the keyboard hook, return FALSE if it was not installed
141 */
142
143Bool
144winInstallKeyboardHookLL (void)
145{
146  OSVERSIONINFO		osvi = {0};
147
148  /* Get operating system version information */
149  osvi.dwOSVersionInfoSize = sizeof (osvi);
150  GetVersionEx (&osvi);
151
152  /* Branch on platform ID */
153  switch (osvi.dwPlatformId)
154    {
155    case VER_PLATFORM_WIN32_NT:
156      /* Low-level is supported on NT 4.0 SP3+ only */
157      /* TODO: Return FALSE on NT 4.0 with no SP, SP1, or SP2 */
158      break;
159
160    case VER_PLATFORM_WIN32_WINDOWS:
161      /* Low-level hook is not supported on non-NT */
162      return FALSE;
163    }
164
165  /* Install the hook only once */
166  if (!g_hhookKeyboardLL)
167    g_hhookKeyboardLL = SetWindowsHookEx (WH_KEYBOARD_LL,
168					  winKeyboardMessageHookLL,
169					  g_hInstance,
170					  0);
171
172  return TRUE;
173}
174
175
176/*
177 * Remove the keyboard hook if it is installed
178 */
179
180void
181winRemoveKeyboardHookLL (void)
182{
183  if (g_hhookKeyboardLL)
184    UnhookWindowsHookEx (g_hhookKeyboardLL);
185  g_hhookKeyboardLL = NULL;
186}
187