1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsWindowBase.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,329 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsWindowBase.h" 1.10 + 1.11 +#include "mozilla/MiscEvents.h" 1.12 +#include "nsGkAtoms.h" 1.13 +#include "WinUtils.h" 1.14 +#include "npapi.h" 1.15 + 1.16 +using namespace mozilla; 1.17 +using namespace mozilla::widget; 1.18 + 1.19 +static const wchar_t kUser32LibName[] = L"user32.dll"; 1.20 +bool nsWindowBase::sTouchInjectInitialized = false; 1.21 +InjectTouchInputPtr nsWindowBase::sInjectTouchFuncPtr; 1.22 + 1.23 +bool 1.24 +nsWindowBase::DispatchPluginEvent(const MSG& aMsg) 1.25 +{ 1.26 + if (!PluginHasFocus()) { 1.27 + return false; 1.28 + } 1.29 + WidgetPluginEvent pluginEvent(true, NS_PLUGIN_INPUT_EVENT, this); 1.30 + nsIntPoint point(0, 0); 1.31 + InitEvent(pluginEvent, &point); 1.32 + NPEvent npEvent; 1.33 + npEvent.event = aMsg.message; 1.34 + npEvent.wParam = aMsg.wParam; 1.35 + npEvent.lParam = aMsg.lParam; 1.36 + pluginEvent.pluginEvent = &npEvent; 1.37 + pluginEvent.retargetToFocusedDocument = true; 1.38 + return DispatchWindowEvent(&pluginEvent); 1.39 +} 1.40 + 1.41 +// static 1.42 +bool 1.43 +nsWindowBase::InitTouchInjection() 1.44 +{ 1.45 + if (!sTouchInjectInitialized) { 1.46 + // Initialize touch injection on the first call 1.47 + HMODULE hMod = LoadLibraryW(kUser32LibName); 1.48 + if (!hMod) { 1.49 + return false; 1.50 + } 1.51 + 1.52 + InitializeTouchInjectionPtr func = 1.53 + (InitializeTouchInjectionPtr)GetProcAddress(hMod, "InitializeTouchInjection"); 1.54 + if (!func) { 1.55 + WinUtils::Log("InitializeTouchInjection not available."); 1.56 + return false; 1.57 + } 1.58 + 1.59 + if (!func(TOUCH_INJECT_MAX_POINTS, TOUCH_FEEDBACK_DEFAULT)) { 1.60 + WinUtils::Log("InitializeTouchInjection failure. GetLastError=%d", GetLastError()); 1.61 + return false; 1.62 + } 1.63 + 1.64 + sInjectTouchFuncPtr = 1.65 + (InjectTouchInputPtr)GetProcAddress(hMod, "InjectTouchInput"); 1.66 + if (!sInjectTouchFuncPtr) { 1.67 + WinUtils::Log("InjectTouchInput not available."); 1.68 + return false; 1.69 + } 1.70 + sTouchInjectInitialized = true; 1.71 + } 1.72 + return true; 1.73 +} 1.74 + 1.75 +bool 1.76 +nsWindowBase::InjectTouchPoint(uint32_t aId, nsIntPoint& aPointerScreenPoint, 1.77 + POINTER_FLAGS aFlags, uint32_t aPressure, 1.78 + uint32_t aOrientation) 1.79 +{ 1.80 + if (aId > TOUCH_INJECT_MAX_POINTS) { 1.81 + WinUtils::Log("Pointer ID exceeds maximum. See TOUCH_INJECT_MAX_POINTS."); 1.82 + return false; 1.83 + } 1.84 + 1.85 + POINTER_TOUCH_INFO info; 1.86 + memset(&info, 0, sizeof(POINTER_TOUCH_INFO)); 1.87 + 1.88 + info.touchFlags = TOUCH_FLAG_NONE; 1.89 + info.touchMask = TOUCH_MASK_CONTACTAREA|TOUCH_MASK_ORIENTATION|TOUCH_MASK_PRESSURE; 1.90 + info.pressure = aPressure; 1.91 + info.orientation = aOrientation; 1.92 + 1.93 + info.pointerInfo.pointerFlags = aFlags; 1.94 + info.pointerInfo.pointerType = PT_TOUCH; 1.95 + info.pointerInfo.pointerId = aId; 1.96 + info.pointerInfo.ptPixelLocation.x = WinUtils::LogToPhys(aPointerScreenPoint.x); 1.97 + info.pointerInfo.ptPixelLocation.y = WinUtils::LogToPhys(aPointerScreenPoint.y); 1.98 + 1.99 + info.rcContact.top = info.pointerInfo.ptPixelLocation.y - 2; 1.100 + info.rcContact.bottom = info.pointerInfo.ptPixelLocation.y + 2; 1.101 + info.rcContact.left = info.pointerInfo.ptPixelLocation.x - 2; 1.102 + info.rcContact.right = info.pointerInfo.ptPixelLocation.x + 2; 1.103 + 1.104 + if (!sInjectTouchFuncPtr(1, &info)) { 1.105 + WinUtils::Log("InjectTouchInput failure. GetLastError=%d", GetLastError()); 1.106 + return false; 1.107 + } 1.108 + return true; 1.109 +} 1.110 + 1.111 +nsresult 1.112 +nsWindowBase::SynthesizeNativeTouchPoint(uint32_t aPointerId, 1.113 + nsIWidget::TouchPointerState aPointerState, 1.114 + nsIntPoint aPointerScreenPoint, 1.115 + double aPointerPressure, 1.116 + uint32_t aPointerOrientation) 1.117 +{ 1.118 + if (!InitTouchInjection()) { 1.119 + return NS_ERROR_NOT_IMPLEMENTED; 1.120 + } 1.121 + 1.122 + bool hover = aPointerState & TOUCH_HOVER; 1.123 + bool contact = aPointerState & TOUCH_CONTACT; 1.124 + bool remove = aPointerState & TOUCH_REMOVE; 1.125 + bool cancel = aPointerState & TOUCH_CANCEL; 1.126 + 1.127 + // win api expects a value from 0 to 1024. aPointerPressure is a value 1.128 + // from 0.0 to 1.0. 1.129 + uint32_t pressure = (uint32_t)ceil(aPointerPressure * 1024); 1.130 + 1.131 + // If we already know about this pointer id get it's record 1.132 + PointerInfo* info = mActivePointers.Get(aPointerId); 1.133 + 1.134 + // We know about this pointer, send an update 1.135 + if (info) { 1.136 + POINTER_FLAGS flags = POINTER_FLAG_UPDATE; 1.137 + if (hover) { 1.138 + flags |= POINTER_FLAG_INRANGE; 1.139 + } else if (contact) { 1.140 + flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_INRANGE; 1.141 + } else if (remove) { 1.142 + flags = POINTER_FLAG_UP; 1.143 + // Remove the pointer from our tracking list. This is nsAutPtr wrapped, 1.144 + // so shouldn't leak. 1.145 + mActivePointers.Remove(aPointerId); 1.146 + } 1.147 + 1.148 + if (cancel) { 1.149 + flags |= POINTER_FLAG_CANCELED; 1.150 + } 1.151 + 1.152 + return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags, 1.153 + pressure, aPointerOrientation) ? 1.154 + NS_ERROR_UNEXPECTED : NS_OK; 1.155 + } 1.156 + 1.157 + // Missing init state, error out 1.158 + if (remove || cancel) { 1.159 + return NS_ERROR_INVALID_ARG; 1.160 + } 1.161 + 1.162 + // Create a new pointer 1.163 + info = new PointerInfo(aPointerId, aPointerScreenPoint); 1.164 + 1.165 + POINTER_FLAGS flags = POINTER_FLAG_INRANGE; 1.166 + if (contact) { 1.167 + flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_DOWN; 1.168 + } 1.169 + 1.170 + mActivePointers.Put(aPointerId, info); 1.171 + return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags, 1.172 + pressure, aPointerOrientation) ? 1.173 + NS_ERROR_UNEXPECTED : NS_OK; 1.174 +} 1.175 + 1.176 +// static 1.177 +PLDHashOperator 1.178 +nsWindowBase::CancelTouchPoints(const unsigned int& aPointerId, nsAutoPtr<PointerInfo>& aInfo, void* aUserArg) 1.179 +{ 1.180 + nsWindowBase* self = static_cast<nsWindowBase*>(aUserArg); 1.181 + self->InjectTouchPoint(aInfo.get()->mPointerId, aInfo.get()->mPosition, POINTER_FLAG_CANCELED); 1.182 + return (PLDHashOperator)(PL_DHASH_NEXT|PL_DHASH_REMOVE); 1.183 +} 1.184 + 1.185 +nsresult 1.186 +nsWindowBase::ClearNativeTouchSequence() 1.187 +{ 1.188 + if (!sTouchInjectInitialized) { 1.189 + return NS_OK; 1.190 + } 1.191 + 1.192 + // cancel all input points 1.193 + mActivePointers.Enumerate(CancelTouchPoints, (void*)this); 1.194 + 1.195 + nsBaseWidget::ClearNativeTouchSequence(); 1.196 + 1.197 + return NS_OK; 1.198 +} 1.199 + 1.200 +bool 1.201 +nsWindowBase::DispatchCommandEvent(uint32_t aEventCommand) 1.202 +{ 1.203 + nsCOMPtr<nsIAtom> command; 1.204 + switch (aEventCommand) { 1.205 + case APPCOMMAND_BROWSER_BACKWARD: 1.206 + command = nsGkAtoms::Back; 1.207 + break; 1.208 + case APPCOMMAND_BROWSER_FORWARD: 1.209 + command = nsGkAtoms::Forward; 1.210 + break; 1.211 + case APPCOMMAND_BROWSER_REFRESH: 1.212 + command = nsGkAtoms::Reload; 1.213 + break; 1.214 + case APPCOMMAND_BROWSER_STOP: 1.215 + command = nsGkAtoms::Stop; 1.216 + break; 1.217 + case APPCOMMAND_BROWSER_SEARCH: 1.218 + command = nsGkAtoms::Search; 1.219 + break; 1.220 + case APPCOMMAND_BROWSER_FAVORITES: 1.221 + command = nsGkAtoms::Bookmarks; 1.222 + break; 1.223 + case APPCOMMAND_BROWSER_HOME: 1.224 + command = nsGkAtoms::Home; 1.225 + break; 1.226 + case APPCOMMAND_CLOSE: 1.227 + command = nsGkAtoms::Close; 1.228 + break; 1.229 + case APPCOMMAND_FIND: 1.230 + command = nsGkAtoms::Find; 1.231 + break; 1.232 + case APPCOMMAND_HELP: 1.233 + command = nsGkAtoms::Help; 1.234 + break; 1.235 + case APPCOMMAND_NEW: 1.236 + command = nsGkAtoms::New; 1.237 + break; 1.238 + case APPCOMMAND_OPEN: 1.239 + command = nsGkAtoms::Open; 1.240 + break; 1.241 + case APPCOMMAND_PRINT: 1.242 + command = nsGkAtoms::Print; 1.243 + break; 1.244 + case APPCOMMAND_SAVE: 1.245 + command = nsGkAtoms::Save; 1.246 + break; 1.247 + case APPCOMMAND_FORWARD_MAIL: 1.248 + command = nsGkAtoms::ForwardMail; 1.249 + break; 1.250 + case APPCOMMAND_REPLY_TO_MAIL: 1.251 + command = nsGkAtoms::ReplyToMail; 1.252 + break; 1.253 + case APPCOMMAND_SEND_MAIL: 1.254 + command = nsGkAtoms::SendMail; 1.255 + break; 1.256 + default: 1.257 + return false; 1.258 + } 1.259 + WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, command, this); 1.260 + 1.261 + InitEvent(event); 1.262 + return DispatchWindowEvent(&event); 1.263 +} 1.264 + 1.265 +bool 1.266 +nsWindowBase::HandleAppCommandMsg(WPARAM aWParam, 1.267 + LPARAM aLParam, 1.268 + LRESULT *aRetValue) 1.269 +{ 1.270 + uint32_t appCommand = GET_APPCOMMAND_LPARAM(aLParam); 1.271 + uint32_t contentCommandMessage = NS_EVENT_NULL; 1.272 + // XXX After we implement KeyboardEvent.key, we should dispatch the 1.273 + // key event if (GET_DEVICE_LPARAM(lParam) == FAPPCOMMAND_KEY) is. 1.274 + switch (appCommand) 1.275 + { 1.276 + case APPCOMMAND_BROWSER_BACKWARD: 1.277 + case APPCOMMAND_BROWSER_FORWARD: 1.278 + case APPCOMMAND_BROWSER_REFRESH: 1.279 + case APPCOMMAND_BROWSER_STOP: 1.280 + case APPCOMMAND_BROWSER_SEARCH: 1.281 + case APPCOMMAND_BROWSER_FAVORITES: 1.282 + case APPCOMMAND_BROWSER_HOME: 1.283 + case APPCOMMAND_CLOSE: 1.284 + case APPCOMMAND_FIND: 1.285 + case APPCOMMAND_HELP: 1.286 + case APPCOMMAND_NEW: 1.287 + case APPCOMMAND_OPEN: 1.288 + case APPCOMMAND_PRINT: 1.289 + case APPCOMMAND_SAVE: 1.290 + case APPCOMMAND_FORWARD_MAIL: 1.291 + case APPCOMMAND_REPLY_TO_MAIL: 1.292 + case APPCOMMAND_SEND_MAIL: 1.293 + // We shouldn't consume the message always because if we don't handle 1.294 + // the message, the sender (typically, utility of keyboard or mouse) 1.295 + // may send other key messages which indicate well known shortcut key. 1.296 + if (DispatchCommandEvent(appCommand)) { 1.297 + // tell the driver that we handled the event 1.298 + *aRetValue = 1; 1.299 + return true; 1.300 + } 1.301 + break; 1.302 + 1.303 + // Use content command for following commands: 1.304 + case APPCOMMAND_COPY: 1.305 + contentCommandMessage = NS_CONTENT_COMMAND_COPY; 1.306 + break; 1.307 + case APPCOMMAND_CUT: 1.308 + contentCommandMessage = NS_CONTENT_COMMAND_CUT; 1.309 + break; 1.310 + case APPCOMMAND_PASTE: 1.311 + contentCommandMessage = NS_CONTENT_COMMAND_PASTE; 1.312 + break; 1.313 + case APPCOMMAND_REDO: 1.314 + contentCommandMessage = NS_CONTENT_COMMAND_REDO; 1.315 + break; 1.316 + case APPCOMMAND_UNDO: 1.317 + contentCommandMessage = NS_CONTENT_COMMAND_UNDO; 1.318 + break; 1.319 + } 1.320 + 1.321 + if (contentCommandMessage) { 1.322 + WidgetContentCommandEvent contentCommand(true, contentCommandMessage, 1.323 + this); 1.324 + DispatchWindowEvent(&contentCommand); 1.325 + // tell the driver that we handled the event 1.326 + *aRetValue = 1; 1.327 + return true; 1.328 + } 1.329 + 1.330 + // default = false - tell the driver that the event was not handled 1.331 + return false; 1.332 +}