зеркало из https://github.com/mozilla/gecko-dev.git
Bug 672175 part.5 Move device specific code to MouseScrollHandler r=jimm
This commit is contained in:
Родитель
82e8e92ed2
Коммит
ee28f178e8
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include <psapi.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
|
@ -25,10 +27,43 @@ static const char* GetBoolName(bool aBool)
|
|||
{
|
||||
return aBool ? "TRUE" : "FALSE";
|
||||
}
|
||||
|
||||
static void LogKeyStateImpl()
|
||||
{
|
||||
if (!PR_LOG_TEST(gMouseScrollLog, PR_LOG_DEBUG)) {
|
||||
return;
|
||||
}
|
||||
BYTE keyboardState[256];
|
||||
if (::GetKeyboardState(keyboardState)) {
|
||||
for (size_t i = 0; i < ArrayLength(keyboardState); i++) {
|
||||
if (keyboardState[i]) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_DEBUG,
|
||||
(" Current key state: keyboardState[0x%02X]=0x%02X (%s)",
|
||||
i, keyboardState[i],
|
||||
((keyboardState[i] & 0x81) == 0x81) ? "Pressed and Toggled" :
|
||||
(keyboardState[i] & 0x80) ? "Pressed" :
|
||||
(keyboardState[i] & 0x01) ? "Toggled" : "Unknown"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_DEBUG,
|
||||
("MouseScroll::Device::Elantech::HandleKeyMessage(): Failed to print "
|
||||
"current keyboard state"));
|
||||
}
|
||||
}
|
||||
|
||||
#define LOG_KEYSTATE() LogKeyStateImpl()
|
||||
#else // PR_LOGGING
|
||||
#define LOG_KEYSTATE()
|
||||
#endif
|
||||
|
||||
MouseScrollHandler* MouseScrollHandler::sInstance = nsnull;
|
||||
|
||||
bool MouseScrollHandler::Device::sFakeScrollableWindowNeeded = false;
|
||||
|
||||
bool MouseScrollHandler::Device::Elantech::sUseSwipeHack = false;
|
||||
bool MouseScrollHandler::Device::Elantech::sUsePinchHack = false;
|
||||
DWORD MouseScrollHandler::Device::Elantech::sZoomUntil = 0;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
|
@ -45,6 +80,7 @@ MouseScrollHandler::Initialize()
|
|||
gMouseScrollLog = PR_NewLogModule("MouseScrollHandlerWidgets");
|
||||
}
|
||||
#endif
|
||||
Device::Init();
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -85,6 +121,8 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg,
|
|||
WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aRetValue, bool &aEatMessage)
|
||||
{
|
||||
Device::Elantech::UpdateZoomUntil();
|
||||
|
||||
switch (msg) {
|
||||
case WM_SETTINGCHANGE:
|
||||
if (!sInstance) {
|
||||
|
@ -95,11 +133,35 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg,
|
|||
sInstance->mSystemSettings.MarkDirty();
|
||||
}
|
||||
return false;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::ProcessMessage(): aWindow=%p, "
|
||||
"msg=%s(0x%04X), wParam=0x%02X, ::GetMessageTime()=%d",
|
||||
aWindow, msg == WM_KEYDOWN ? "WM_KEYDOWN" :
|
||||
msg == WM_KEYUP ? "WM_KEYUP" : "Unknown", msg, wParam,
|
||||
::GetMessageTime()));
|
||||
LOG_KEYSTATE();
|
||||
if (Device::Elantech::HandleKeyMessage(aWindow, msg, wParam)) {
|
||||
*aRetValue = 0;
|
||||
aEatMessage = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::DispatchEvent(nsWindow* aWindow, nsGUIEvent& aEvent)
|
||||
{
|
||||
return aWindow->DispatchWindowEvent(&aEvent);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* SystemSettings
|
||||
|
@ -220,5 +282,362 @@ MouseScrollHandler::UserPrefs::MarkDirty()
|
|||
mInitialized = false;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Device
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::Device::GetWorkaroundPref(const char* aPrefName,
|
||||
bool aValueIfAutomatic)
|
||||
{
|
||||
if (!aPrefName) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::GetWorkaroundPref(): Failed, aPrefName is NULL"));
|
||||
return aValueIfAutomatic;
|
||||
}
|
||||
|
||||
PRInt32 lHackValue = 0;
|
||||
if (NS_FAILED(Preferences::GetInt(aPrefName, &lHackValue))) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::GetWorkaroundPref(): Preferences::GetInt() failed,"
|
||||
" aPrefName=\"%s\", aValueIfAutomatic=%s",
|
||||
aPrefName, GetBoolName(aValueIfAutomatic)));
|
||||
return aValueIfAutomatic;
|
||||
}
|
||||
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::GetWorkaroundPref(): Succeeded, "
|
||||
"aPrefName=\"%s\", aValueIfAutomatic=%s, lHackValue=%d",
|
||||
aPrefName, GetBoolName(aValueIfAutomatic), lHackValue));
|
||||
|
||||
switch (lHackValue) {
|
||||
case 0: // disabled
|
||||
return false;
|
||||
case 1: // enabled
|
||||
return true;
|
||||
default: // -1: autodetect
|
||||
return aValueIfAutomatic;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
MouseScrollHandler::Device::Init()
|
||||
{
|
||||
sFakeScrollableWindowNeeded =
|
||||
GetWorkaroundPref("ui.trackpoint_hack.enabled",
|
||||
(TrackPoint::IsDriverInstalled() ||
|
||||
UltraNav::IsObsoleteDriverInstalled()));
|
||||
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::Init(): sFakeScrollableWindowNeeded=%s",
|
||||
GetBoolName(sFakeScrollableWindowNeeded)));
|
||||
|
||||
Elantech::Init();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Device::Elantech
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* static */
|
||||
void
|
||||
MouseScrollHandler::Device::Elantech::Init()
|
||||
{
|
||||
PRInt32 version = GetDriverMajorVersion();
|
||||
bool needsHack =
|
||||
Device::GetWorkaroundPref("ui.elantech_gesture_hacks.enabled",
|
||||
version != 0);
|
||||
sUseSwipeHack = needsHack && version <= 7;
|
||||
sUsePinchHack = needsHack && version <= 8;
|
||||
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::Elantech::Init(): version=%d, sUseSwipeHack=%s, "
|
||||
"sUsePinchHack=%s",
|
||||
version, GetBoolName(sUseSwipeHack), GetBoolName(sUsePinchHack)));
|
||||
}
|
||||
|
||||
/* static */
|
||||
PRInt32
|
||||
MouseScrollHandler::Device::Elantech::GetDriverMajorVersion()
|
||||
{
|
||||
PRUnichar buf[40];
|
||||
// The driver version is found in one of these two registry keys.
|
||||
bool foundKey =
|
||||
WinUtils::GetRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Elantech\\MainOption",
|
||||
L"DriverVersion",
|
||||
buf, sizeof buf);
|
||||
if (!foundKey) {
|
||||
foundKey =
|
||||
WinUtils::GetRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Elantech",
|
||||
L"DriverVersion",
|
||||
buf, sizeof buf);
|
||||
}
|
||||
|
||||
if (!foundKey) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Assume that the major version number can be found just after a space
|
||||
// or at the start of the string.
|
||||
for (PRUnichar* p = buf; *p; p++) {
|
||||
if (*p >= L'0' && *p <= L'9' && (p == buf || *(p - 1) == L' ')) {
|
||||
return wcstol(p, NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::Device::Elantech::IsHelperWindow(HWND aWnd)
|
||||
{
|
||||
// The helper window cannot be distinguished based on its window class, so we
|
||||
// need to check if it is owned by the helper process, ETDCtrl.exe.
|
||||
|
||||
const PRUnichar* filenameSuffix = L"\\etdctrl.exe";
|
||||
const int filenameSuffixLength = 12;
|
||||
|
||||
DWORD pid;
|
||||
::GetWindowThreadProcessId(aWnd, &pid);
|
||||
|
||||
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (!hProcess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
PRUnichar path[256] = {L'\0'};
|
||||
if (::GetProcessImageFileNameW(hProcess, path, ArrayLength(path))) {
|
||||
int pathLength = lstrlenW(path);
|
||||
if (pathLength >= filenameSuffixLength) {
|
||||
if (lstrcmpiW(path + pathLength - filenameSuffixLength,
|
||||
filenameSuffix) == 0) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
::CloseHandle(hProcess);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::Device::Elantech::HandleKeyMessage(nsWindow* aWindow,
|
||||
UINT aMsg,
|
||||
WPARAM aWParam)
|
||||
{
|
||||
// The Elantech touchpad driver understands three-finger swipe left and
|
||||
// right gestures, and translates them into Page Up and Page Down key
|
||||
// events for most applications. For Firefox 3.6, it instead sends
|
||||
// Alt+Left and Alt+Right to trigger browser back/forward actions. As
|
||||
// with the Thinkpad Driver hack in nsWindow::Create, the change in
|
||||
// HWND structure makes Firefox not trigger the driver's heuristics
|
||||
// any longer.
|
||||
//
|
||||
// The Elantech driver actually sends these messages for a three-finger
|
||||
// swipe right:
|
||||
//
|
||||
// WM_KEYDOWN virtual_key = 0xCC or 0xFF (depending on driver version)
|
||||
// WM_KEYDOWN virtual_key = VK_NEXT
|
||||
// WM_KEYUP virtual_key = VK_NEXT
|
||||
// WM_KEYUP virtual_key = 0xCC or 0xFF
|
||||
//
|
||||
// so we use the 0xCC or 0xFF key modifier to detect whether the Page Down
|
||||
// is due to the gesture rather than a regular Page Down keypress. We then
|
||||
// pretend that we should dispatch "Go Forward" command. Similarly
|
||||
// for VK_PRIOR and "Go Back" command.
|
||||
if (sUseSwipeHack &&
|
||||
(aWParam == VK_NEXT || aWParam == VK_PRIOR) &&
|
||||
(IS_VK_DOWN(0xFF) || IS_VK_DOWN(0xCC))) {
|
||||
if (aMsg == WM_KEYDOWN) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::Elantech::HandleKeyMessage(): Dispatching "
|
||||
"%s command event",
|
||||
aWParam == VK_NEXT ? "Forward" : "Back"));
|
||||
|
||||
nsCommandEvent commandEvent(true, nsGkAtoms::onAppCommand,
|
||||
(aWParam == VK_NEXT) ? nsGkAtoms::Forward : nsGkAtoms::Back, aWindow);
|
||||
aWindow->InitEvent(commandEvent);
|
||||
MouseScrollHandler::DispatchEvent(aWindow, commandEvent);
|
||||
}
|
||||
#ifdef PR_LOGGING
|
||||
else {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::Elantech::HandleKeyMessage(): Consumed"));
|
||||
}
|
||||
#endif
|
||||
return true; // consume the message (doesn't need to dispatch key events)
|
||||
}
|
||||
|
||||
// Version 8 of the Elantech touchpad driver sends these messages for
|
||||
// zoom gestures:
|
||||
//
|
||||
// WM_KEYDOWN virtual_key = 0xCC time = 10
|
||||
// WM_KEYDOWN virtual_key = VK_CONTROL time = 10
|
||||
// WM_MOUSEWHEEL time = ::GetTickCount()
|
||||
// WM_KEYUP virtual_key = VK_CONTROL time = 10
|
||||
// WM_KEYUP virtual_key = 0xCC time = 10
|
||||
//
|
||||
// The result of this is that we process all of the WM_KEYDOWN/WM_KEYUP
|
||||
// messages first because their timestamps make them appear to have
|
||||
// been sent before the WM_MOUSEWHEEL message. To work around this,
|
||||
// we store the current time when we process the WM_KEYUP message and
|
||||
// assume that any WM_MOUSEWHEEL message with a timestamp before that
|
||||
// time is one that should be processed as if the Control key was down.
|
||||
if (sUsePinchHack && aMsg == WM_KEYUP &&
|
||||
aWParam == VK_CONTROL && ::GetMessageTime() == 10) {
|
||||
// We look only at the bottom 31 bits of the system tick count since
|
||||
// GetMessageTime returns a LONG, which is signed, so we want values
|
||||
// that are more easily comparable.
|
||||
sZoomUntil = ::GetTickCount() & 0x7FFFFFFF;
|
||||
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::Elantech::HandleKeyMessage(): sZoomUntil=%d",
|
||||
sZoomUntil));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
MouseScrollHandler::Device::Elantech::UpdateZoomUntil()
|
||||
{
|
||||
if (!sZoomUntil) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For the Elantech Touchpad Zoom Gesture Hack, we should check that the
|
||||
// system time (32-bit milliseconds) hasn't wrapped around. Otherwise we
|
||||
// might get into the situation where wheel events for the next 50 days of
|
||||
// system uptime are assumed to be Ctrl+Wheel events. (It is unlikely that
|
||||
// we would get into that state, because the system would already need to be
|
||||
// up for 50 days and the Control key message would need to be processed just
|
||||
// before the system time overflow and the wheel message just after.)
|
||||
//
|
||||
// We also take the chance to reset sZoomUntil if we simply have passed that
|
||||
// time.
|
||||
LONG msgTime = ::GetMessageTime();
|
||||
if ((sZoomUntil >= 0x3fffffffu && DWORD(msgTime) < 0x40000000u) ||
|
||||
(sZoomUntil < DWORD(msgTime))) {
|
||||
sZoomUntil = 0;
|
||||
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::Elantech::UpdateZoomUntil(): "
|
||||
"sZoomUntil was reset"));
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::Device::Elantech::IsZooming()
|
||||
{
|
||||
// Assume the Control key is down if the Elantech touchpad has sent the
|
||||
// mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages. (See the comment in
|
||||
// OnKeyUp.)
|
||||
return (sZoomUntil && static_cast<DWORD>(::GetMessageTime()) < sZoomUntil);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Device::TrackPoint
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::Device::TrackPoint::IsDriverInstalled()
|
||||
{
|
||||
if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Lenovo\\TrackPoint")) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::TrackPoint::IsDriverInstalled(): "
|
||||
"Lenovo's TrackPoint driver is found"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Alps\\Apoint\\TrackPoint")) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::TrackPoint::IsDriverInstalled(): "
|
||||
"Alps's TrackPoint driver is found"));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Device::UltraNav
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MouseScrollHandler::Device::UltraNav::IsObsoleteDriverInstalled()
|
||||
{
|
||||
if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Lenovo\\UltraNav")) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): "
|
||||
"Lenovo's UltraNav driver is found"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool installed = false;
|
||||
if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB")) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): "
|
||||
"Synaptics's UltraNav (USB) driver is found"));
|
||||
installed = true;
|
||||
} else if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): "
|
||||
"Synaptics's UltraNav (PS/2) driver is found"));
|
||||
installed = true;
|
||||
}
|
||||
|
||||
if (!installed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PRUnichar buf[40];
|
||||
bool foundKey =
|
||||
WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
|
||||
L"Software\\Synaptics\\SynTP\\Install",
|
||||
L"DriverVersion",
|
||||
buf, sizeof buf);
|
||||
if (!foundKey) {
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): "
|
||||
"Failed to get UltraNav driver version"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int majorVersion = wcstol(buf, NULL, 10);
|
||||
int minorVersion = 0;
|
||||
PRUnichar* p = wcschr(buf, L'.');
|
||||
if (p) {
|
||||
minorVersion = wcstol(p + 1, NULL, 10);
|
||||
}
|
||||
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
|
||||
("MouseScroll::Device::UltraNav::IsObsoleteDriverInstalled(): "
|
||||
"found driver version = %d.%d",
|
||||
majorVersion, minorVersion));
|
||||
return majorVersion < 15 || majorVersion == 15 && minorVersion == 0;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <windows.h>
|
||||
|
||||
class nsWindow;
|
||||
class nsGUIEvent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
@ -37,6 +38,12 @@ private:
|
|||
|
||||
static MouseScrollHandler* sInstance;
|
||||
|
||||
/**
|
||||
* DispatchEvent() dispatches aEvent on aWindow.
|
||||
*
|
||||
* @return TRUE if the event was consumed. Otherwise, FALSE.
|
||||
*/
|
||||
static bool DispatchEvent(nsWindow* aWindow, nsGUIEvent& aEvent);
|
||||
public:
|
||||
class SystemSettings {
|
||||
public:
|
||||
|
@ -113,6 +120,91 @@ public:
|
|||
|
||||
private:
|
||||
UserPrefs mUserPrefs;
|
||||
|
||||
public:
|
||||
|
||||
class Device {
|
||||
public:
|
||||
class Elantech {
|
||||
public:
|
||||
/**
|
||||
* GetDriverMajorVersion() returns the installed driver's major version.
|
||||
* If Elantech's driver was installed, returns 0.
|
||||
*/
|
||||
static PRInt32 GetDriverMajorVersion();
|
||||
|
||||
/**
|
||||
* IsHelperWindow() checks whether aWnd is a helper window of Elantech's
|
||||
* touchpad. Returns TRUE if so. Otherwise, FALSE.
|
||||
*/
|
||||
static bool IsHelperWindow(HWND aWnd);
|
||||
|
||||
/**
|
||||
* Key message handler for Elantech's hack. Returns TRUE if the message
|
||||
* is consumed by this handler. Otherwise, FALSE.
|
||||
*/
|
||||
static bool HandleKeyMessage(nsWindow* aWindow,
|
||||
UINT aMsg,
|
||||
WPARAM aWParam);
|
||||
|
||||
static void UpdateZoomUntil();
|
||||
static bool IsZooming();
|
||||
|
||||
static void Init();
|
||||
|
||||
static bool IsPinchHackNeeded() { return sUsePinchHack; }
|
||||
|
||||
|
||||
private:
|
||||
// Whether to enable the Elantech swipe gesture hack.
|
||||
static bool sUseSwipeHack;
|
||||
// Whether to enable the Elantech pinch-to-zoom gesture hack.
|
||||
static bool sUsePinchHack;
|
||||
static DWORD sZoomUntil;
|
||||
}; // class Elantech
|
||||
|
||||
class TrackPoint {
|
||||
public:
|
||||
/**
|
||||
* IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
|
||||
* Otherwise, returns FALSE.
|
||||
*/
|
||||
static bool IsDriverInstalled();
|
||||
}; // class TrackPoint
|
||||
|
||||
class UltraNav {
|
||||
public:
|
||||
/**
|
||||
* IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
|
||||
* is installed on the environment.
|
||||
* Returns TRUE if it was installed. Otherwise, FALSE.
|
||||
*/
|
||||
static bool IsObsoleteDriverInstalled();
|
||||
}; // class UltraNav
|
||||
|
||||
static void Init();
|
||||
|
||||
static bool IsFakeScrollableWindowNeeded()
|
||||
{
|
||||
return sFakeScrollableWindowNeeded;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Gets the bool value of aPrefName used to enable or disable an input
|
||||
* workaround (like the Trackpoint hack). The pref can take values 0 (for
|
||||
* disabled), 1 (for enabled) or -1 (to automatically detect whether to
|
||||
* enable the workaround).
|
||||
*
|
||||
* @param aPrefName The name of the pref.
|
||||
* @param aValueIfAutomatic Whether the given input workaround should be
|
||||
* enabled by default.
|
||||
*/
|
||||
static bool GetWorkaroundPref(const char* aPrefName,
|
||||
bool aValueIfAutomatic);
|
||||
|
||||
static bool sFakeScrollableWindowNeeded;
|
||||
}; // class Device
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
|
|
|
@ -271,14 +271,8 @@ BYTE nsWindow::sLastMouseButton = 0;
|
|||
// Trim heap on minimize. (initialized, but still true.)
|
||||
int nsWindow::sTrimOnMinimize = 2;
|
||||
|
||||
// Default value for Trackpoint hack (used when the pref is set to -1).
|
||||
bool nsWindow::sDefaultTrackPointHack = false;
|
||||
// Default value for general window class (used when the pref is the empty string).
|
||||
const char* nsWindow::sDefaultMainWindowClass = kClassNameGeneral;
|
||||
// Whether to enable the Elantech swipe gesture hack.
|
||||
bool nsWindow::sUseElantechSwipeHack = false;
|
||||
// Whether to enable the Elantech pinch-to-zoom gesture hack.
|
||||
bool nsWindow::sUseElantechPinchHack = false;
|
||||
|
||||
// If we're using D3D9, this will not be allowed during initial 5 seconds.
|
||||
bool nsWindow::sAllowD3D9 = false;
|
||||
|
@ -404,7 +398,6 @@ nsWindow::nsWindow() : nsBaseWidget()
|
|||
mOldExStyle = 0;
|
||||
mPainting = 0;
|
||||
mLastKeyboardLayout = 0;
|
||||
mAssumeWheelIsZoomUntil = 0;
|
||||
mBlurSuppressLevel = 0;
|
||||
mLastPaintEndTime = TimeStamp::Now();
|
||||
#ifdef MOZ_XUL
|
||||
|
@ -435,7 +428,6 @@ nsWindow::nsWindow() : nsBaseWidget()
|
|||
sIsOleInitialized = TRUE;
|
||||
}
|
||||
NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
|
||||
InitInputWorkaroundPrefDefaults();
|
||||
MouseScrollHandler::Initialize();
|
||||
// Init titlebar button info for custom frames.
|
||||
nsUXThemeData::InitTitlebarInfo();
|
||||
|
@ -601,7 +593,7 @@ nsWindow::Create(nsIWidget *aParent,
|
|||
|
||||
if (mWindowType != eWindowType_plugin &&
|
||||
mWindowType != eWindowType_invisible &&
|
||||
UseTrackPointHack()) {
|
||||
MouseScrollHandler::Device::IsFakeScrollableWindowNeeded()) {
|
||||
// Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
|
||||
//
|
||||
// We create two zero-sized windows as descendants of the top-level window,
|
||||
|
@ -4487,24 +4479,6 @@ static bool CleartypeSettingChanged()
|
|||
bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
|
||||
LRESULT *aRetValue)
|
||||
{
|
||||
// For the Elantech Touchpad Zoom Gesture Hack, we should check that the
|
||||
// system time (32-bit milliseconds) hasn't wrapped around. Otherwise we
|
||||
// might get into the situation where wheel events for the next 50 days of
|
||||
// system uptime are assumed to be Ctrl+Wheel events. (It is unlikely that
|
||||
// we would get into that state, because the system would already need to be
|
||||
// up for 50 days and the Control key message would need to be processed just
|
||||
// before the system time overflow and the wheel message just after.)
|
||||
//
|
||||
// We also take the chance to reset mAssumeWheelIsZoomUntil if we simply have
|
||||
// passed that time.
|
||||
if (mAssumeWheelIsZoomUntil) {
|
||||
LONG msgTime = ::GetMessageTime();
|
||||
if ((mAssumeWheelIsZoomUntil >= 0x3fffffffu && DWORD(msgTime) < 0x40000000u) ||
|
||||
(mAssumeWheelIsZoomUntil < DWORD(msgTime))) {
|
||||
mAssumeWheelIsZoomUntil = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// (Large blocks of code should be broken out into OnEvent handlers.)
|
||||
if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
|
||||
return true;
|
||||
|
@ -6388,13 +6362,10 @@ nsWindow::OnMouseWheelInternal(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
|
|||
|
||||
// Assume the Control key is down if the Elantech touchpad has sent the
|
||||
// mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages. (See the comment in
|
||||
// OnKeyUp.)
|
||||
bool isControl;
|
||||
if (mAssumeWheelIsZoomUntil &&
|
||||
static_cast<DWORD>(::GetMessageTime()) < mAssumeWheelIsZoomUntil) {
|
||||
isControl = true;
|
||||
} else {
|
||||
isControl = modKeyState.mIsControlDown;
|
||||
// MouseScrollHandler::Device::Elantech::HandleKeyMessage().)
|
||||
if (!modKeyState.mIsControlDown) {
|
||||
modKeyState.mIsControlDown =
|
||||
MouseScrollHandler::Device::Elantech::IsZooming();
|
||||
}
|
||||
|
||||
// Create line (or page) scroll event.
|
||||
|
@ -6404,7 +6375,7 @@ nsWindow::OnMouseWheelInternal(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
|
|||
// test event.
|
||||
InitEvent(scrollEvent);
|
||||
scrollEvent.isShift = modKeyState.mIsShiftDown;
|
||||
scrollEvent.isControl = isControl;
|
||||
scrollEvent.isControl = modKeyState.mIsControlDown;
|
||||
scrollEvent.isMeta = false;
|
||||
scrollEvent.isAlt = modKeyState.mIsAltDown;
|
||||
|
||||
|
@ -6578,37 +6549,6 @@ bool nsWindow::IsRedirectedKeyDownMessage(const MSG &aMsg)
|
|||
WinUtils::GetScanCode(aMsg.lParam));
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::PerformElantechSwipeGestureHack(UINT& aVirtualKeyCode,
|
||||
nsModifierKeyState& aModKeyState)
|
||||
{
|
||||
// The Elantech touchpad driver understands three-finger swipe left and
|
||||
// right gestures, and translates them into Page Up and Page Down key
|
||||
// events for most applications. For Firefox 3.6, it instead sends
|
||||
// Alt+Left and Alt+Right to trigger browser back/forward actions. As
|
||||
// with the Thinkpad Driver hack in nsWindow::Create, the change in
|
||||
// HWND structure makes Firefox not trigger the driver's heuristics
|
||||
// any longer.
|
||||
//
|
||||
// The Elantech driver actually sends these messages for a three-finger
|
||||
// swipe right:
|
||||
//
|
||||
// WM_KEYDOWN virtual_key = 0xCC or 0xFF (depending on driver version)
|
||||
// WM_KEYDOWN virtual_key = VK_NEXT
|
||||
// WM_KEYUP virtual_key = VK_NEXT
|
||||
// WM_KEYUP virtual_key = 0xCC or 0xFF
|
||||
//
|
||||
// so we use the 0xCC or 0xFF key modifier to detect whether the Page Down
|
||||
// is due to the gesture rather than a regular Page Down keypress. We then
|
||||
// pretend that we were went an Alt+Right keystroke instead. Similarly
|
||||
// for VK_PRIOR and Alt+Left.
|
||||
if ((aVirtualKeyCode == VK_NEXT || aVirtualKeyCode == VK_PRIOR) &&
|
||||
(IS_VK_DOWN(0xFF) || IS_VK_DOWN(0xCC))) {
|
||||
aModKeyState.mIsAltDown = true;
|
||||
aVirtualKeyCode = aVirtualKeyCode == VK_NEXT ? VK_RIGHT : VK_LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nsWindow::OnKeyDown peeks into the message queue and pulls out
|
||||
* WM_CHAR messages for processing. During testing we don't want to
|
||||
|
@ -6626,10 +6566,6 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
|
|||
aMsg.wParam != VK_PROCESSKEY ? aMsg.wParam : ::ImmGetVirtualKey(mWnd);
|
||||
gKbdLayout.OnKeyDown(virtualKeyCode);
|
||||
|
||||
if (sUseElantechSwipeHack) {
|
||||
PerformElantechSwipeGestureHack(virtualKeyCode, aModKeyState);
|
||||
}
|
||||
|
||||
// Use only DOMKeyCode for XP processing.
|
||||
// Use virtualKeyCode for gKbdLayout and native processing.
|
||||
UINT DOMKeyCode = nsIMM32Handler::IsComposingOn(this) ?
|
||||
|
@ -6971,34 +6907,6 @@ LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
|
|||
{
|
||||
UINT virtualKeyCode = aMsg.wParam;
|
||||
|
||||
if (sUseElantechSwipeHack) {
|
||||
PerformElantechSwipeGestureHack(virtualKeyCode, aModKeyState);
|
||||
}
|
||||
|
||||
if (sUseElantechPinchHack) {
|
||||
// Version 8 of the Elantech touchpad driver sends these messages for
|
||||
// zoom gestures:
|
||||
//
|
||||
// WM_KEYDOWN virtual_key = 0xCC time = 10
|
||||
// WM_KEYDOWN virtual_key = VK_CONTROL time = 10
|
||||
// WM_MOUSEWHEEL time = ::GetTickCount()
|
||||
// WM_KEYUP virtual_key = VK_CONTROL time = 10
|
||||
// WM_KEYUP virtual_key = 0xCC time = 10
|
||||
//
|
||||
// The result of this is that we process all of the WM_KEYDOWN/WM_KEYUP
|
||||
// messages first because their timestamps make them appear to have
|
||||
// been sent before the WM_MOUSEWHEEL message. To work around this,
|
||||
// we store the current time when we process the WM_KEYUP message and
|
||||
// assume that any WM_MOUSEWHEEL message with a timestamp before that
|
||||
// time is one that should be processed as if the Control key was down.
|
||||
if (virtualKeyCode == VK_CONTROL && aMsg.time == 10) {
|
||||
// We look only at the bottom 31 bits of the system tick count since
|
||||
// GetMessageTime returns a LONG, which is signed, so we want values
|
||||
// that are more easily comparable.
|
||||
mAssumeWheelIsZoomUntil = ::GetTickCount() & 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
|
||||
("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
|
||||
|
||||
|
@ -7405,37 +7313,6 @@ bool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Determine whether the given HWND is the handle for the Elantech helper
|
||||
// window. The helper window cannot be distinguished based on its
|
||||
// window class, so we need to check if it is owned by the helper process,
|
||||
// ETDCtrl.exe.
|
||||
static bool IsElantechHelperWindow(HWND aHWND)
|
||||
{
|
||||
const PRUnichar* filenameSuffix = L"\\etdctrl.exe";
|
||||
const int filenameSuffixLength = 12;
|
||||
|
||||
DWORD pid;
|
||||
::GetWindowThreadProcessId(aHWND, &pid);
|
||||
|
||||
bool result = false;
|
||||
|
||||
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (hProcess) {
|
||||
PRUnichar path[256] = {L'\0'};
|
||||
if (GetProcessImageFileName(hProcess, path, ArrayLength(path))) {
|
||||
int pathLength = lstrlenW(path);
|
||||
if (pathLength >= filenameSuffixLength) {
|
||||
if (lstrcmpiW(path + pathLength - filenameSuffixLength, filenameSuffix) == 0) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
::CloseHandle(hProcess);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* OnMouseWheel() is called when ProcessMessage() handles WM_MOUSEWHEEL,
|
||||
* WM_MOUSEHWHEEL and also OnScroll() tries to emulate mouse wheel action for
|
||||
|
@ -7484,7 +7361,8 @@ nsWindow::OnMouseWheel(UINT aMsg, WPARAM aWParam, LPARAM aLParam,
|
|||
return;
|
||||
}
|
||||
|
||||
if (sUseElantechPinchHack && IsElantechHelperWindow(underCursorWnd)) {
|
||||
if (MouseScrollHandler::Device::Elantech::IsPinchHackNeeded() &&
|
||||
MouseScrollHandler::Device::Elantech::IsHelperWindow(underCursorWnd)) {
|
||||
// The Elantech driver places a window right underneath the cursor
|
||||
// when sending a WM_MOUSEWHEEL event to us as part of a pinch-to-zoom
|
||||
// gesture. We detect that here, and search for our window that would
|
||||
|
@ -8625,123 +8503,6 @@ void nsWindow::GetMainWindowClass(nsAString& aClass)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Boolean value of a pref used to enable or disable an input
|
||||
* workaround (like the Trackpoint hack). The pref can take values 0 (for
|
||||
* disabled), 1 (for enabled) or -1 (to automatically detect whether to
|
||||
* enable the workaround).
|
||||
*
|
||||
* @param aPrefName The name of the pref.
|
||||
* @param aValueIfAutomatic Whether the given input workaround should be
|
||||
* enabled by default.
|
||||
*/
|
||||
bool nsWindow::GetInputWorkaroundPref(const char* aPrefName,
|
||||
bool aValueIfAutomatic)
|
||||
{
|
||||
if (!aPrefName) {
|
||||
return aValueIfAutomatic;
|
||||
}
|
||||
|
||||
PRInt32 lHackValue = 0;
|
||||
if (NS_SUCCEEDED(Preferences::GetInt(aPrefName, &lHackValue))) {
|
||||
switch (lHackValue) {
|
||||
case 0: // disabled
|
||||
return false;
|
||||
case 1: // enabled
|
||||
return true;
|
||||
default: // -1: autodetect
|
||||
break;
|
||||
}
|
||||
}
|
||||
return aValueIfAutomatic;
|
||||
}
|
||||
|
||||
bool nsWindow::UseTrackPointHack()
|
||||
{
|
||||
return GetInputWorkaroundPref("ui.trackpoint_hack.enabled",
|
||||
sDefaultTrackPointHack);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsObsoleteSynapticsDriver()
|
||||
{
|
||||
PRUnichar buf[40];
|
||||
bool foundKey = WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
|
||||
L"Software\\Synaptics\\SynTP\\Install",
|
||||
L"DriverVersion",
|
||||
buf,
|
||||
sizeof buf);
|
||||
if (!foundKey)
|
||||
return false;
|
||||
|
||||
int majorVersion = wcstol(buf, NULL, 10);
|
||||
int minorVersion = 0;
|
||||
PRUnichar* p = wcschr(buf, L'.');
|
||||
if (p) {
|
||||
minorVersion = wcstol(p + 1, NULL, 10);
|
||||
}
|
||||
return majorVersion < 15 || majorVersion == 15 && minorVersion == 0;
|
||||
}
|
||||
|
||||
static PRInt32
|
||||
GetElantechDriverMajorVersion()
|
||||
{
|
||||
PRUnichar buf[40];
|
||||
// The driver version is found in one of these two registry keys.
|
||||
bool foundKey = WinUtils::GetRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Elantech\\MainOption",
|
||||
L"DriverVersion",
|
||||
buf,
|
||||
sizeof buf);
|
||||
if (!foundKey)
|
||||
foundKey = WinUtils::GetRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Elantech",
|
||||
L"DriverVersion",
|
||||
buf,
|
||||
sizeof buf);
|
||||
|
||||
if (!foundKey)
|
||||
return false;
|
||||
|
||||
// Assume that the major version number can be found just after a space
|
||||
// or at the start of the string.
|
||||
for (PRUnichar* p = buf; *p; p++) {
|
||||
if (*p >= L'0' && *p <= L'9' && (p == buf || *(p - 1) == L' ')) {
|
||||
return wcstol(p, NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nsWindow::InitInputWorkaroundPrefDefaults()
|
||||
{
|
||||
PRUint32 elantechDriverVersion = GetElantechDriverMajorVersion();
|
||||
|
||||
if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Lenovo\\TrackPoint")) {
|
||||
sDefaultTrackPointHack = true;
|
||||
} else if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Lenovo\\UltraNav")) {
|
||||
sDefaultTrackPointHack = true;
|
||||
} else if (WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Alps\\Apoint\\TrackPoint")) {
|
||||
sDefaultTrackPointHack = true;
|
||||
} else if ((WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB") ||
|
||||
WinUtils::HasRegistryKey(HKEY_CURRENT_USER,
|
||||
L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) &&
|
||||
IsObsoleteSynapticsDriver()) {
|
||||
sDefaultTrackPointHack = true;
|
||||
}
|
||||
|
||||
bool useElantechGestureHacks =
|
||||
GetInputWorkaroundPref("ui.elantech_gesture_hacks.enabled",
|
||||
elantechDriverVersion != 0);
|
||||
sUseElantechSwipeHack = useElantechGestureHacks && elantechDriverVersion <= 7;
|
||||
sUseElantechPinchHack = useElantechGestureHacks && elantechDriverVersion <= 8;
|
||||
}
|
||||
|
||||
LPARAM nsWindow::lParamToScreen(LPARAM lParam)
|
||||
{
|
||||
POINT pt;
|
||||
|
|
|
@ -334,10 +334,6 @@ protected:
|
|||
void ResetLayout();
|
||||
void InvalidateNonClientRegion();
|
||||
HRGN ExcludeNonClientFromPaintRegion(HRGN aRegion);
|
||||
static void InitInputWorkaroundPrefDefaults();
|
||||
static bool GetInputWorkaroundPref(const char* aPrefName, bool aValueIfAutomatic);
|
||||
static bool UseTrackPointHack();
|
||||
static void PerformElantechSwipeGestureHack(UINT& aVirtualKeyCode, nsModifierKeyState& aModKeyState);
|
||||
static void GetMainWindowClass(nsAString& aClass);
|
||||
bool HasGlass() const {
|
||||
return mTransparencyMode == eTransparencyGlass ||
|
||||
|
@ -522,10 +518,7 @@ protected:
|
|||
static bool sJustGotActivate;
|
||||
static bool sIsInMouseCapture;
|
||||
static int sTrimOnMinimize;
|
||||
static bool sDefaultTrackPointHack;
|
||||
static const char* sDefaultMainWindowClass;
|
||||
static bool sUseElantechSwipeHack;
|
||||
static bool sUseElantechPinchHack;
|
||||
static bool sAllowD3D9;
|
||||
|
||||
// Always use the helper method to read this property. See bug 603793.
|
||||
|
|
Загрузка…
Ссылка в новой задаче