WebClient.cpp 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. //
  2. // Copyright (c) 2014-2016, THUNDERBEAST GAMES LLC All rights reserved
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #ifdef ATOMIC_PLATFORM_WINDOWS
  23. #include <windows.h>
  24. #undef LoadString
  25. #endif
  26. #include <include/cef_app.h>
  27. #include <include/cef_client.h>
  28. #include <include/cef_browser.h>
  29. #include <include/wrapper/cef_helpers.h>
  30. #include <include/base/cef_bind.h>
  31. #include <include/wrapper/cef_closure_task.h>
  32. #include "include/wrapper/cef_message_router.h"
  33. #include <Atomic/Core/ProcessUtils.h>
  34. #include <Atomic/Core/CoreEvents.h>
  35. #include <Atomic/IO/Log.h>
  36. #include <Atomic/Input/Input.h>
  37. #include <Atomic/Graphics/Graphics.h>
  38. #include "Internal/WebAppBrowser.h"
  39. #include "WebBrowserHost.h"
  40. #include "WebMessageHandler.h"
  41. #include "WebClient.h"
  42. #include "WebKeyboard.h"
  43. #include "WebViewEvents.h"
  44. #include "WebString.h"
  45. #include <SDL/include/SDL.h>
  46. #ifdef ATOMIC_PLATFORM_LINUX
  47. #ifndef SDL_VIDEO_DRIVER_X11
  48. #define SDL_VIDEO_DRIVER_X11
  49. #endif
  50. #endif
  51. #include <ThirdParty/SDL/include/SDL_syswm.h>
  52. namespace Atomic
  53. {
  54. #ifdef ATOMIC_PLATFORM_OSX
  55. void* GetNSWindowContentView(void* window);
  56. #endif
  57. class WebClientPrivate : public CefClient,
  58. public CefLifeSpanHandler,
  59. public CefLoadHandler,
  60. public CefDisplayHandler,
  61. public CefRequestHandler,
  62. public CefKeyboardHandler
  63. {
  64. friend class WebClient;
  65. public:
  66. WebClientPrivate(WebClient* client)
  67. {
  68. webClient_ = client;
  69. webBrowserHost_ = webClient_->GetSubsystem<WebBrowserHost>();
  70. CefMessageRouterConfig config;
  71. config.js_query_function = WebBrowserHost::GetJSMessageQueryFunctionName().CString();
  72. config.js_cancel_function = WebBrowserHost::GetJSMessageQueryCancelFunctionName().CString();
  73. browserSideRouter_ = CefMessageRouterBrowserSide::Create(config);
  74. }
  75. virtual ~WebClientPrivate()
  76. {
  77. }
  78. CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE
  79. {
  80. if (webClient_.Null() || webClient_->renderHandler_.Null())
  81. return nullptr;
  82. return webClient_->renderHandler_->GetCEFRenderHandler();
  83. }
  84. CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE
  85. {
  86. return this;
  87. }
  88. CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE
  89. {
  90. return this;
  91. }
  92. CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE
  93. {
  94. return this;
  95. }
  96. CefRefPtr<CefRequestHandler> GetRequestHandler() OVERRIDE
  97. {
  98. return this;
  99. }
  100. CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE
  101. {
  102. return this;
  103. }
  104. // CefKeyboardHandler
  105. virtual bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
  106. const CefKeyEvent& event,
  107. CefEventHandle os_event,
  108. bool* is_keyboard_shortcut) OVERRIDE
  109. {
  110. return false;
  111. }
  112. // CefRequestHandler methods
  113. void OnRenderViewReady(CefRefPtr<CefBrowser> browser) OVERRIDE
  114. {
  115. }
  116. bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
  117. CefRefPtr<CefFrame> frame,
  118. CefRefPtr<CefRequest> request,
  119. bool is_redirect) OVERRIDE
  120. {
  121. CEF_REQUIRE_UI_THREAD();
  122. browserSideRouter_->OnBeforeBrowse(browser, frame);
  123. return false;
  124. }
  125. bool OnProcessMessageReceived(
  126. CefRefPtr<CefBrowser> browser,
  127. CefProcessId source_process,
  128. CefRefPtr<CefProcessMessage> message) OVERRIDE
  129. {
  130. CEF_REQUIRE_UI_THREAD();
  131. const CefString& message_name = message->GetName();
  132. if (message_name == "atomic_eval_javascript_result")
  133. {
  134. if (webClient_.Null())
  135. return false;
  136. unsigned evalID = (unsigned) message->GetArgumentList()->GetInt(0);
  137. bool result = message->GetArgumentList()->GetBool(1);
  138. String value;
  139. ConvertCEFString(message->GetArgumentList()->GetString(2), value);
  140. webClient_->EvalJavaScriptResult(evalID, result, value);
  141. return true;
  142. }
  143. if (browserSideRouter_->OnProcessMessageReceived(browser, source_process, message))
  144. {
  145. return true;
  146. }
  147. return false;
  148. }
  149. void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
  150. TerminationStatus status) OVERRIDE
  151. {
  152. CEF_REQUIRE_UI_THREAD();
  153. browserSideRouter_->OnRenderProcessTerminated(browser);
  154. }
  155. // CefLoadHandler
  156. void OnLoadStart(CefRefPtr<CefBrowser> browser,
  157. CefRefPtr<CefFrame> frame, TransitionType transition_type) OVERRIDE
  158. {
  159. if (webClient_.Null() || !frame->IsMain())
  160. return;
  161. VariantMap eventData;
  162. eventData[WebViewLoadStart::P_CLIENT] = webClient_;
  163. CefString cefURL = frame->GetURL();
  164. String url;
  165. ConvertCEFString(cefURL, url);
  166. eventData[WebViewLoadStart::P_URL] = url;
  167. webClient_->SendEvent(E_WEBVIEWLOADSTART, eventData);
  168. }
  169. void OnLoadEnd(CefRefPtr<CefBrowser> browser,
  170. CefRefPtr<CefFrame> frame,
  171. int httpStatusCode) OVERRIDE
  172. {
  173. if (webClient_.Null() || !frame->IsMain())
  174. return;
  175. VariantMap eventData;
  176. eventData[WebViewLoadEnd::P_CLIENT] = webClient_;
  177. CefString cefURL = frame->GetURL();
  178. String url;
  179. ConvertCEFString(cefURL, url);
  180. eventData[WebViewLoadEnd::P_URL] = url;
  181. webClient_->SendEvent(E_WEBVIEWLOADEND, eventData);
  182. }
  183. void OnLoadError(CefRefPtr<CefBrowser> browser,
  184. CefRefPtr<CefFrame> frame,
  185. ErrorCode errorCode,
  186. const CefString& errorText,
  187. const CefString& failedUrl) OVERRIDE
  188. {
  189. if (webClient_.Null())
  190. return;
  191. }
  192. void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
  193. bool isLoading,
  194. bool canGoBack,
  195. bool canGoForward) OVERRIDE
  196. {
  197. if (webClient_.Null())
  198. return;
  199. VariantMap eventData;
  200. eventData[WebViewLoadStateChange::P_CLIENT] = webClient_;
  201. eventData[WebViewLoadStateChange::P_LOADING] = isLoading;
  202. eventData[WebViewLoadStateChange::P_CANGOBACK] = canGoBack;
  203. eventData[WebViewLoadStateChange::P_CANGOFORWARD] = canGoForward;
  204. webClient_->SendEvent(E_WEBVIEWLOADSTATECHANGE, eventData);
  205. }
  206. // CefDisplayHandler
  207. void OnAddressChange(CefRefPtr<CefBrowser> browser,
  208. CefRefPtr<CefFrame> frame,
  209. const CefString& url) OVERRIDE
  210. {
  211. if (webClient_.Null() || !frame->IsMain())
  212. return;
  213. VariantMap eventData;
  214. eventData[WebViewAddressChange::P_CLIENT] = webClient_;
  215. String _url;
  216. ConvertCEFString(url, _url);
  217. eventData[WebViewAddressChange::P_URL] = _url;
  218. webClient_->SendEvent(E_WEBVIEWADDRESSCHANGE, eventData);
  219. }
  220. void OnTitleChange(CefRefPtr<CefBrowser> browser,
  221. const CefString& title) OVERRIDE
  222. {
  223. if (webClient_.Null())
  224. return;
  225. VariantMap eventData;
  226. eventData[WebViewTitleChange::P_CLIENT] = webClient_;
  227. String _title;
  228. ConvertCEFString(title, _title);
  229. eventData[WebViewTitleChange::P_TITLE] = _title;
  230. webClient_->SendEvent(E_WEBVIEWTITLECHANGE, eventData);
  231. }
  232. ///
  233. // Called to display a console message. Return true to stop the message from
  234. // being output to the console.
  235. ///
  236. /*--cef(optional_param=message,optional_param=source)--*/
  237. virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
  238. const CefString& message,
  239. const CefString& source,
  240. int line) OVERRIDE
  241. {
  242. if (webClient_.Null())
  243. return false;
  244. String _message;
  245. ConvertCEFString(message, _message);
  246. String _source;
  247. ConvertCEFString(source, _source);
  248. ATOMIC_LOGINFOF("WebViewJS: %s (%s:%i)", _message.CString(), _source.CString(), line);
  249. return false;
  250. }
  251. bool CreateBrowser(const String& initialURL, int width, int height)
  252. {
  253. if (browser_.get())
  254. {
  255. ATOMIC_LOGERROR("WebClient::CreateBrowser - Browser already created");
  256. return false;
  257. }
  258. if (webClient_->renderHandler_.Null())
  259. {
  260. ATOMIC_LOGERROR("WebClient::CreateBrowser - No render handler specified");
  261. return false;
  262. }
  263. CefWindowInfo windowInfo;
  264. CefBrowserSettings browserSettings;
  265. browserSettings.webgl = STATE_ENABLED;
  266. browserSettings.file_access_from_file_urls = STATE_ENABLED;
  267. browserSettings.universal_access_from_file_urls = STATE_ENABLED;
  268. browserSettings.web_security = WebBrowserHost::GetWebSecurity() ? STATE_ENABLED : STATE_DISABLED;
  269. browserSettings.javascript_access_clipboard = STATE_ENABLED;
  270. browserSettings.javascript_dom_paste = STATE_ENABLED;
  271. windowInfo.width = width;
  272. windowInfo.height = height;
  273. windowInfo.transparent_painting_enabled = 1;
  274. Graphics* graphics = webClient_->GetSubsystem<Graphics>();
  275. if (graphics)
  276. {
  277. SDL_Window* sdlWindow = static_cast<SDL_Window*>(graphics->GetSDLWindow());
  278. SDL_SysWMinfo info;
  279. SDL_VERSION(&info.version);
  280. if(SDL_GetWindowWMInfo(sdlWindow, &info))
  281. {
  282. #ifdef ATOMIC_PLATFORM_OSX
  283. NSView* view = (NSView*) GetNSWindowContentView(info.info.cocoa.window);
  284. windowInfo.SetAsWindowless(view, false);
  285. #endif
  286. #ifdef ATOMIC_PLATFORM_WINDOWS
  287. windowInfo.SetAsWindowless(info.info.win.window, /*transparent*/ true);
  288. #endif
  289. #ifdef ATOMIC_PLATFORM_LINUX
  290. if ( info.subsystem == SDL_SYSWM_X11 )
  291. windowInfo.SetAsWindowless(info.info.x11.window, true);
  292. #endif
  293. }
  294. }
  295. else
  296. {
  297. #ifndef ATOMIC_PLATFORM_LINUX
  298. // headless
  299. windowInfo.SetAsWindowless(nullptr, true);
  300. #endif
  301. }
  302. // TODO: There seems to be a CEF bug when loading a string into a browser
  303. // which was created with an empty URL, this workaround gets things going
  304. // NOTE: I also tried loading the string, delaying 5 seconds and still won't
  305. // load a string until a URL has been passed into the view
  306. String _initialURL = initialLoadString_.Length() ? "x" : initialURL;
  307. webClient_->renderHandler_->SetSize(width, height);
  308. CefRefPtr<CefBrowser> browser = CefBrowserHost::CreateBrowserSync(windowInfo, this,
  309. _initialURL.CString(), browserSettings, nullptr);
  310. if (!browser.get())
  311. return false;
  312. browser_ = browser;
  313. if (initialLoadString_.Length())
  314. {
  315. webClient_->LoadString(initialLoadString_, initialLoadStringURL_);
  316. }
  317. return true;
  318. }
  319. // CefLifeSpanHandler methods:
  320. virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE
  321. {
  322. CEF_REQUIRE_UI_THREAD();
  323. }
  324. virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE
  325. {
  326. return false;
  327. }
  328. virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE
  329. {
  330. CEF_REQUIRE_UI_THREAD();
  331. browser_ = nullptr;
  332. }
  333. virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
  334. CefRefPtr<CefFrame> frame,
  335. const CefString& target_url,
  336. const CefString& target_frame_name,
  337. CefLifeSpanHandler::WindowOpenDisposition target_disposition,
  338. bool user_gesture,
  339. const CefPopupFeatures& popupFeatures,
  340. CefWindowInfo& windowInfo,
  341. CefRefPtr<CefClient>& client,
  342. CefBrowserSettings& settings,
  343. bool* no_javascript_access) OVERRIDE
  344. {
  345. // Called on the IO thread, cancel and convert to popup request
  346. assert(!CefCurrentlyOn(TID_UI));
  347. // Execute on the UI thread.
  348. CefPostTask(TID_UI,
  349. base::Bind(&WebClientPrivate::OnPopupRequest, this, target_url));
  350. return true;
  351. }
  352. void OnPopupRequest(const CefString& target_url)
  353. {
  354. if (webClient_.Null())
  355. return;
  356. String url;
  357. ConvertCEFString(target_url, url);
  358. VariantMap eventData;
  359. eventData[WebViewPopupRequest::P_CLIENT] = webClient_;
  360. eventData[WebViewPopupRequest::P_URL] = url;
  361. webClient_->SendEvent(E_WEBVIEWPOPUPREQUEST, eventData);
  362. }
  363. void CloseBrowser(bool force_close)
  364. {
  365. if (!CefCurrentlyOn(TID_UI))
  366. {
  367. // Execute on the UI thread.
  368. CefPostTask(TID_UI,
  369. base::Bind(&WebClientPrivate::CloseBrowser, this, force_close));
  370. return;
  371. }
  372. if (!browser_.get())
  373. return;
  374. browser_->GetHost()->CloseBrowser(force_close);
  375. }
  376. void SetInitialLoadString(const String& loadString, const String& url)
  377. {
  378. initialLoadString_ = loadString;
  379. initialLoadStringURL_ = url;
  380. }
  381. IMPLEMENT_REFCOUNTING(WebClientPrivate);
  382. void ClearReferences()
  383. {
  384. browser_ = nullptr;
  385. webBrowserHost_ = nullptr;
  386. webClient_ = nullptr;
  387. browserSideRouter_ = nullptr;
  388. }
  389. private:
  390. String initialLoadString_;
  391. String initialLoadStringURL_;
  392. CefRefPtr<CefBrowser> browser_;
  393. WeakPtr<WebBrowserHost> webBrowserHost_;
  394. WeakPtr<WebClient> webClient_;
  395. CefRefPtr<CefMessageRouterBrowserSide> browserSideRouter_;
  396. };
  397. WebClient::WebClient(Context* context) : Object(context)
  398. {
  399. d_ = new WebClientPrivate(this);
  400. d_->AddRef();
  401. SubscribeToEvent(E_WEBVIEWGLOBALPROPERTIESCHANGED, ATOMIC_HANDLER(WebClient, HandleWebViewGlobalPropertiesChanged));
  402. }
  403. WebClient::~WebClient()
  404. {
  405. if (d_)
  406. {
  407. List<SharedPtr<WebMessageHandler>>::Iterator itr = messageHandlers_.Begin();
  408. while (itr != messageHandlers_.End())
  409. {
  410. CefMessageRouterBrowserSide::Handler* handler = static_cast<CefMessageRouterBrowserSide::Handler*>((*itr)->GetCefHandler());
  411. d_->browserSideRouter_->RemoveHandler(handler);
  412. itr++;
  413. }
  414. d_->CloseBrowser(true);
  415. d_->ClearReferences();
  416. d_->Release();
  417. }
  418. d_ = nullptr;
  419. renderHandler_ = 0;
  420. }
  421. void WebClient::SendMouseClickEvent(int x, int y, unsigned button, bool mouseUp, unsigned modifier, int clickCount) const
  422. {
  423. if (!d_->browser_.get())
  424. return;
  425. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  426. CefMouseEvent mevent;
  427. mevent.x = x;
  428. mevent.y = y;
  429. mevent.modifiers = 0;
  430. //MBT_LEFT = 0,
  431. //MBT_MIDDLE,
  432. //MBT_RIGHT,
  433. host->SendMouseClickEvent(mevent, (CefBrowserHost::MouseButtonType) button, mouseUp, clickCount);
  434. }
  435. void WebClient::SendMousePressEvent(int x, int y, unsigned button, unsigned modifier, int clickCount) const
  436. {
  437. SendMouseClickEvent(x, y, button, false, modifier, clickCount);
  438. SendMouseClickEvent(x, y, button, true, modifier, clickCount);
  439. }
  440. void WebClient::SendMouseMoveEvent(int x, int y, unsigned modifier, bool mouseLeave) const
  441. {
  442. if (!d_->browser_.get())
  443. return;
  444. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  445. CefMouseEvent mevent;
  446. mevent.x = x;
  447. mevent.y = y;
  448. mevent.modifiers = 0;
  449. Input* input = GetSubsystem<Input>();
  450. if (input->GetMouseButtonDown(MOUSEB_LEFT))
  451. mevent.modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
  452. if (input->GetMouseButtonDown(MOUSEB_MIDDLE))
  453. mevent.modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
  454. if (input->GetMouseButtonDown(MOUSEB_RIGHT))
  455. mevent.modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
  456. host->SendMouseMoveEvent(mevent, mouseLeave);
  457. }
  458. void WebClient::SendMouseWheelEvent(int x, int y, unsigned modifier,int deltaX, int deltaY) const
  459. {
  460. if (!d_->browser_.get())
  461. return;
  462. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  463. CefMouseEvent mevent;
  464. mevent.x = x;
  465. mevent.y = y;
  466. mevent.modifiers = 0;
  467. deltaY = -deltaY * 5;
  468. #ifndef ATOMIC_PLATFORM_OSX
  469. deltaY *= 5;
  470. #endif
  471. host->SendMouseWheelEvent(mevent, deltaX, deltaY);
  472. }
  473. /*
  474. EVENTFLAG_CAPS_LOCK_ON = 1 << 0,
  475. EVENTFLAG_SHIFT_DOWN = 1 << 1,
  476. EVENTFLAG_CONTROL_DOWN = 1 << 2,
  477. EVENTFLAG_ALT_DOWN = 1 << 3,
  478. EVENTFLAG_LEFT_MOUSE_BUTTON = 1 << 4,
  479. EVENTFLAG_MIDDLE_MOUSE_BUTTON = 1 << 5,
  480. EVENTFLAG_RIGHT_MOUSE_BUTTON = 1 << 6,
  481. // Mac OS-X command key.
  482. EVENTFLAG_COMMAND_DOWN = 1 << 7,
  483. EVENTFLAG_NUM_LOCK_ON = 1 << 8,
  484. EVENTFLAG_IS_KEY_PAD = 1 << 9,
  485. EVENTFLAG_IS_LEFT = 1 << 10,
  486. EVENTFLAG_IS_RIGHT = 1 << 11,
  487. } cef_event_flags_t;
  488. */
  489. void WebClient::SendKeyEvent(const StringHash eventType, VariantMap& eventData)
  490. {
  491. if (!d_->browser_.get())
  492. return;
  493. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  494. CefKeyEvent keyEvent;
  495. if (!ConvertKeyEvent(GetSubsystem<Input>(), eventType, eventData, keyEvent))
  496. return;
  497. host->SendKeyEvent(keyEvent);
  498. #ifdef ATOMIC_PLATFORM_WINDOWS
  499. // RETURN KEY: We need to send both keydown and char for return key
  500. // this allows it to be used both to confirm entry on popups,
  501. // while also being used for text input
  502. if (keyEvent.windows_key_code == 13)
  503. {
  504. keyEvent.type = KEYEVENT_CHAR;
  505. host->SendKeyEvent(keyEvent);
  506. }
  507. #endif
  508. #ifdef ATOMIC_PLATFORM_OSX
  509. // RETURN KEY: We need to send both keydown and char for return key
  510. // this allows it to be used both to confirm entry on popups,
  511. // while also being used for text input
  512. if (keyEvent.native_key_code == 36)
  513. {
  514. keyEvent.type = KEYEVENT_CHAR;
  515. host->SendKeyEvent(keyEvent);
  516. }
  517. // Send an empty key event on OSX, which seems to fix
  518. // keyboard problems on OSX with cefclient
  519. // ./cefclient --off-screen-rendering-enabled
  520. // return does not work at all on cef client with offscreen
  521. // bad interaction with arrow keys (for example here, after
  522. // hitting arrow keys, return/text takes a couple presses to register
  523. memset((void*)&keyEvent, 0, sizeof(keyEvent));
  524. keyEvent.type = KEYEVENT_KEYDOWN;
  525. keyEvent.modifiers = 0;
  526. keyEvent.native_key_code = 0;
  527. host->SendKeyEvent(keyEvent);
  528. #endif
  529. #ifdef ATOMIC_PLATFORM_LINUX
  530. if (keyEvent.windows_key_code == 0x0D)
  531. {
  532. keyEvent.type = KEYEVENT_CHAR;
  533. host->SendKeyEvent(keyEvent);
  534. }
  535. #endif
  536. }
  537. void WebClient::SendTextInputEvent(const StringHash eventType, VariantMap& eventData)
  538. {
  539. if (!d_->browser_.get())
  540. return;
  541. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  542. CefKeyEvent keyEvent;
  543. if (!ConvertTextInputEvent(eventType, eventData, keyEvent))
  544. return;
  545. host->SendKeyEvent(keyEvent);
  546. }
  547. void WebClient::SendFocusEvent(bool focus)
  548. {
  549. if (!d_->browser_.get())
  550. return;
  551. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  552. host->SendFocusEvent(focus);
  553. }
  554. // Javascript
  555. void WebClient::ExecuteJavaScript(const String& script)
  556. {
  557. if (!d_->browser_.get())
  558. return;
  559. d_->browser_->GetMainFrame()->ExecuteJavaScript(CefString(script.CString()), "", 0);
  560. }
  561. void WebClient::EvalJavaScript(unsigned evalID, const String& script)
  562. {
  563. if (!d_->browser_.get())
  564. return;
  565. // Create the message object.
  566. CefRefPtr<CefProcessMessage> msg= CefProcessMessage::Create("atomic_eval_javascript");
  567. // Retrieve the argument list object.
  568. CefRefPtr<CefListValue> args = msg->GetArgumentList();
  569. // Populate the argument values.
  570. args->SetInt(0, (int) evalID);
  571. args->SetString(1, CefString(script.CString()));
  572. // Send the process message to the render process.
  573. // Use PID_BROWSER instead when sending a message to the browser process.
  574. d_->browser_->SendProcessMessage(PID_RENDERER, msg);
  575. }
  576. void WebClient::EvalJavaScriptResult(unsigned evalID, bool result, const String& value)
  577. {
  578. using namespace WebViewJSEvalResult;
  579. VariantMap eventData;
  580. eventData[P_CLIENT] = this;
  581. eventData[P_EVALID] = evalID;
  582. eventData[P_RESULT] = result;
  583. eventData[P_VALUE] = value;
  584. SendEvent(E_WEBVIEWJSEVALRESULT, eventData);
  585. }
  586. void WebClient::AddMessageHandler(WebMessageHandler* handler, bool first)
  587. {
  588. SharedPtr<WebMessageHandler> _handler(handler);
  589. if (handler->GetWebClient())
  590. {
  591. ATOMIC_LOGWARNING("WebClient::AddMessageHandler - message handler already added to another client");
  592. return;
  593. }
  594. if (messageHandlers_.Contains(_handler))
  595. {
  596. ATOMIC_LOGWARNING("WebClient::AddMessageHandler - message handler already added to this client");
  597. return;
  598. }
  599. _handler->SetWebClient(this);
  600. messageHandlers_.Push(_handler);
  601. d_->browserSideRouter_->AddHandler(static_cast<CefMessageRouterBrowserSide::Handler*>(handler->GetCefHandler()), first);
  602. }
  603. void WebClient::RemoveMessageHandler(WebMessageHandler* handler)
  604. {
  605. SharedPtr<WebMessageHandler> _handler(handler);
  606. List<SharedPtr<WebMessageHandler>>::Iterator itr = messageHandlers_.Find(_handler);
  607. if (itr == messageHandlers_.End())
  608. {
  609. ATOMIC_LOGWARNING("WebClient::RemoveMessageHandler - message handler not found");
  610. return;
  611. }
  612. d_->browserSideRouter_->RemoveHandler(static_cast<CefMessageRouterBrowserSide::Handler*>(handler->GetCefHandler()));
  613. messageHandlers_.Erase(itr);
  614. }
  615. // Navigation
  616. void WebClient::LoadURL(const String& url)
  617. {
  618. if (!d_->browser_.get())
  619. {
  620. return;
  621. }
  622. CefString _url(url.CString());
  623. d_->browser_->GetMainFrame()->LoadURL(_url);
  624. }
  625. void WebClient::LoadString(const String& source, const String& url)
  626. {
  627. if (!d_->browser_.get())
  628. {
  629. d_->SetInitialLoadString(source, url);
  630. return;
  631. }
  632. // We need to make sure global properties are updated when loading web content from source string
  633. // This is handled differently internally then we requests
  634. UpdateGlobalProperties();
  635. d_->browser_->GetMainFrame()->LoadString(source.CString(), url.CString());
  636. }
  637. void WebClient::GoBack()
  638. {
  639. if (!d_->browser_.get())
  640. return;
  641. d_->browser_->GoBack();
  642. }
  643. void WebClient::GoForward()
  644. {
  645. if (!d_->browser_.get())
  646. return;
  647. d_->browser_->GoForward();
  648. }
  649. bool WebClient::IsLoading()
  650. {
  651. if (!d_->browser_.get())
  652. return false;
  653. return d_->browser_->IsLoading();
  654. }
  655. void WebClient::Reload()
  656. {
  657. if (!d_->browser_.get())
  658. return;
  659. d_->browser_->Reload();
  660. }
  661. void WebClient::ShortcutCut()
  662. {
  663. if (!d_->browser_.get())
  664. return;
  665. d_->browser_->GetFocusedFrame()->Cut();
  666. }
  667. void WebClient::ShortcutCopy()
  668. {
  669. if (!d_->browser_.get())
  670. return;
  671. d_->browser_->GetFocusedFrame()->Copy();
  672. }
  673. void WebClient::ShortcutPaste()
  674. {
  675. if (!d_->browser_.get())
  676. return;
  677. d_->browser_->GetFocusedFrame()->Paste();
  678. }
  679. void WebClient::ShortcutSelectAll()
  680. {
  681. if (!d_->browser_.get())
  682. return;
  683. d_->browser_->GetFocusedFrame()->SelectAll();
  684. }
  685. void WebClient::ShortcutUndo()
  686. {
  687. if (!d_->browser_.get())
  688. return;
  689. d_->browser_->GetFocusedFrame()->Undo();
  690. }
  691. void WebClient::ShortcutRedo()
  692. {
  693. if (!d_->browser_.get())
  694. return;
  695. d_->browser_->GetFocusedFrame()->Redo();
  696. }
  697. void WebClient::ShortcutDelete()
  698. {
  699. if (!d_->browser_.get())
  700. return;
  701. d_->browser_->GetFocusedFrame()->Delete();
  702. }
  703. void WebClient::WasResized()
  704. {
  705. if (!d_->browser_.get())
  706. return;
  707. CefRefPtr<CefBrowserHost> host = d_->browser_->GetHost();
  708. host->WasResized();;
  709. }
  710. bool WebClient::CreateBrowser(const String& initialURL, int width, int height)
  711. {
  712. bool result = d_->CreateBrowser(initialURL, width, height);
  713. return result;
  714. }
  715. void WebClient::UpdateGlobalProperties()
  716. {
  717. if (!d_->browser_.get())
  718. return;
  719. CefRefPtr<CefDictionaryValue> globalProps;
  720. if (!WebAppBrowser::CreateGlobalProperties(globalProps))
  721. return;
  722. // Create the message object.
  723. CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("atomic_set_globalproperties");
  724. // Retrieve the argument list object.
  725. CefRefPtr<CefListValue> args = msg->GetArgumentList();
  726. args->SetDictionary(0, globalProps);
  727. // Send the process message to the render process.
  728. if (!d_->browser_->SendProcessMessage(PID_RENDERER, msg))
  729. {
  730. ATOMIC_LOGERROR("WebClient::UpdateGlobalProperties - Failed to send message");
  731. }
  732. }
  733. void WebClient::HandleWebViewGlobalPropertiesChanged(StringHash eventType, VariantMap& eventData)
  734. {
  735. UpdateGlobalProperties();
  736. }
  737. void WebClient::SetSize(int width, int height)
  738. {
  739. if (renderHandler_.Null())
  740. return;
  741. if (renderHandler_->GetWidth() == width && renderHandler_->GetHeight() == height)
  742. return;
  743. renderHandler_->SetSize(width, height);
  744. WasResized();
  745. }
  746. void WebClient::SetZoomLevel(float zoomLevel)
  747. {
  748. if (!d_->browser_.get())
  749. return;
  750. d_->browser_->GetHost()->SetZoomLevel(zoomLevel);
  751. }
  752. void WebClient::SetWebRenderHandler(WebRenderHandler* handler)
  753. {
  754. handler->SetWebClient(this);
  755. renderHandler_ = handler;
  756. }
  757. CefClient* WebClient::GetCefClient()
  758. {
  759. return d_;
  760. }
  761. }