diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-22 03:36:37 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-22 03:36:37 +0000 |
commit | 67bfb83fbdd401bba2cfdbe330edebf2b3105a6f (patch) | |
tree | a7ed2dc89b3161efdb13cf5b163aa1a61d2e07b6 /ppapi/examples | |
parent | 88de6c013ddad04c6896f10714c787ce21cf858a (diff) | |
download | chromium_src-67bfb83fbdd401bba2cfdbe330edebf2b3105a6f.zip chromium_src-67bfb83fbdd401bba2cfdbe330edebf2b3105a6f.tar.gz chromium_src-67bfb83fbdd401bba2cfdbe330edebf2b3105a6f.tar.bz2 |
Mouse lock implementation, including the renderer side and the Windows version of the browser side.
BUG=41781
TEST=Manual test in ppapi/examples/mouse_lock
Review URL: http://codereview.chromium.org/7863003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102234 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/examples')
-rwxr-xr-x | ppapi/examples/mouse_lock/mouse_lock.cc | 272 | ||||
-rwxr-xr-x | ppapi/examples/mouse_lock/mouse_lock.html | 25 |
2 files changed, 297 insertions, 0 deletions
diff --git a/ppapi/examples/mouse_lock/mouse_lock.cc b/ppapi/examples/mouse_lock/mouse_lock.cc new file mode 100755 index 0000000..95806cf5 --- /dev/null +++ b/ppapi/examples/mouse_lock/mouse_lock.cc @@ -0,0 +1,272 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <cmath> +#include <stdarg.h> +#include <stdio.h> + +#include "ppapi/c/dev/ppb_console_dev.h" +#include "ppapi/c/ppb_input_event.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/dev/mouse_lock_dev.h" +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/input_event.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/logging.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/var.h" + +class MyInstance : public pp::Instance, public pp::MouseLock_Dev { + public: + explicit MyInstance(PP_Instance instance) + : pp::Instance(instance), + pp::MouseLock_Dev(this), + width_(0), + height_(0), + mouse_locked_(false), + pending_paint_(false), + waiting_for_flush_completion_(false), + callback_factory_(this), + console_(NULL) { + } + virtual ~MyInstance() {} + + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { + console_ = reinterpret_cast<const PPB_Console_Dev*>( + pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE)); + if (!console_) + return false; + + RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | + PP_INPUTEVENT_CLASS_KEYBOARD); + return true; + } + + virtual bool HandleInputEvent(const pp::InputEvent& event) { + switch (event.GetType()) { + case PP_INPUTEVENT_TYPE_MOUSEDOWN: { + pp::MouseInputEvent mouse_event(event); + if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT && + !mouse_locked_) { + LockMouse( + callback_factory_.NewRequiredCallback(&MyInstance::DidLockMouse)); + } else if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT && + mouse_locked_) { + UnlockMouse(); + } + return true; + } + case PP_INPUTEVENT_TYPE_MOUSEMOVE: { + pp::MouseInputEvent mouse_event(event); + mouse_movement_ = mouse_event.GetMovement(); + static unsigned int i = 0; + Log(PP_LOGLEVEL_LOG, "[%d] movementX: %d; movementY: %d\n", i++, + mouse_movement_.x(), mouse_movement_.y()); + Paint(); + return true; + } + case PP_INPUTEVENT_TYPE_KEYDOWN: { + pp::KeyboardInputEvent key_event(event); + // Lock the mouse when the Enter key is pressed. + if (!mouse_locked_ && key_event.GetKeyCode() == 13) { + LockMouse( + callback_factory_.NewRequiredCallback(&MyInstance::DidLockMouse)); + } + return true; + } + default: + return false; + } + } + + virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { + if (position.size().width() == width_ && + position.size().height() == height_) + return; // We don't care about the position, only the size. + + width_ = position.size().width(); + height_ = position.size().height(); + + device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false); + if (!BindGraphics(device_context_)) + return; + + Paint(); + } + + virtual void MouseLockLost() { + if (mouse_locked_) { + mouse_locked_ = false; + Paint(); + } else { + PP_NOTREACHED(); + } + } + + private: + void DidLockMouse(int32_t result) { + mouse_locked_ = result == PP_OK; + mouse_movement_.set_x(0); + mouse_movement_.set_y(0); + Paint(); + } + + void DidFlush(int32_t result) { + waiting_for_flush_completion_ = false; + if (pending_paint_) { + pending_paint_ = false; + Paint(); + } + } + + void Paint() { + if (waiting_for_flush_completion_) { + pending_paint_ = true; + return; + } + + pp::ImageData image = PaintImage(width_, height_); + if (!image.is_null()) { + device_context_.ReplaceContents(&image); + waiting_for_flush_completion_ = true; + device_context_.Flush( + callback_factory_.NewRequiredCallback(&MyInstance::DidFlush)); + } + } + + pp::ImageData PaintImage(int width, int height) { + pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, + pp::Size(width, height), false); + if (image.is_null()) + return image; + + const static int kCenteralSpotRadius = 5; + const static uint32_t kBackgroundColor = 0xfff0f0f0; + const static uint32_t kLockedForegroundColor = 0xfff08080; + const static uint32_t kUnlockedForegroundColor = 0xff80f080; + + int center_x = width / 2; + int center_y = height / 2; + pp::Point vertex(mouse_movement_.x() + center_x, + mouse_movement_.y() + center_y); + pp::Point anchor_1; + pp::Point anchor_2; + enum { + LEFT = 0, + RIGHT = 1, + UP = 2, + DOWN = 3 + } direction; + bool draw_needle = GetDistance(mouse_movement_.x(), mouse_movement_.y(), + 0, 0) > kCenteralSpotRadius; + if (draw_needle) { + if (abs(mouse_movement_.x()) >= abs(mouse_movement_.y())) { + anchor_1.set_x(center_x); + anchor_1.set_y(center_y - kCenteralSpotRadius); + anchor_2.set_x(center_x); + anchor_2.set_y(center_y + kCenteralSpotRadius); + direction = (mouse_movement_.x() < 0) ? LEFT : RIGHT; + if (direction == LEFT) + anchor_1.swap(anchor_2); + } else { + anchor_1.set_x(center_x + kCenteralSpotRadius); + anchor_1.set_y(center_y); + anchor_2.set_x(center_x - kCenteralSpotRadius); + anchor_2.set_y(center_y); + direction = (mouse_movement_.y() < 0) ? UP : DOWN; + if (direction == UP) + anchor_1.swap(anchor_2); + } + } + uint32_t foreground_color = mouse_locked_ ? kLockedForegroundColor : + kUnlockedForegroundColor; + for (int y = 0; y < image.size().height(); ++y) { + for (int x = 0; x < image.size().width(); ++x) { + if (GetDistance(x, y, center_x, center_y) < kCenteralSpotRadius) { + *image.GetAddr32(pp::Point(x, y)) = foreground_color; + continue; + } + if (draw_needle) { + bool within_bound_1 = + ((y - anchor_1.y()) * (vertex.x() - anchor_1.x())) > + ((vertex.y() - anchor_1.y()) * (x - anchor_1.x())); + bool within_bound_2 = + ((y - anchor_2.y()) * (vertex.x() - anchor_2.x())) < + ((vertex.y() - anchor_2.y()) * (x - anchor_2.x())); + bool within_bound_3 = + (direction == UP && y < center_y) || + (direction == DOWN && y > center_y) || + (direction == LEFT && x < center_x) || + (direction == RIGHT && x > center_y); + + if (within_bound_1 && within_bound_2 && within_bound_3) { + *image.GetAddr32(pp::Point(x, y)) = foreground_color; + continue; + } + } + *image.GetAddr32(pp::Point(x, y)) = kBackgroundColor; + } + } + + return image; + } + + double GetDistance(int point_1_x, int point_1_y, + int point_2_x, int point_2_y) { + return sqrt(pow(static_cast<double>(point_1_x - point_2_x), 2) + + pow(static_cast<double>(point_1_y - point_2_y), 2)); + } + + void Log(PP_LogLevel_Dev level, const char* format, ...) { + va_list args; + va_start(args, format); + char buf[512]; + vsnprintf(buf, sizeof(buf) - 1, format, args); + buf[sizeof(buf) - 1] = '\0'; + va_end(args); + + pp::Var value(buf); + console_->Log(pp_instance(), level, value.pp_var()); + } + + int width_; + int height_; + + bool mouse_locked_; + pp::Point mouse_movement_; + + bool pending_paint_; + bool waiting_for_flush_completion_; + + pp::CompletionCallbackFactory<MyInstance> callback_factory_; + + const PPB_Console_Dev* console_; + + pp::Graphics2D device_context_; +}; + +// This object is the global object representing this plugin library as long +// as it is loaded. +class MyModule : public pp::Module { + public: + MyModule() : pp::Module() {} + virtual ~MyModule() {} + + // Override CreateInstance to create your customized Instance object. + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new MyInstance(instance); + } +}; + +namespace pp { + +// Factory function for your specialization of the Module object. +Module* CreateModule() { + return new MyModule(); +} + +} // namespace pp + diff --git a/ppapi/examples/mouse_lock/mouse_lock.html b/ppapi/examples/mouse_lock/mouse_lock.html new file mode 100755 index 0000000..3f8841fa --- /dev/null +++ b/ppapi/examples/mouse_lock/mouse_lock.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright (c) 2011 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + <title>Mouse Lock Example</title> +</head> + +<body title="This tooltip should not be shown if the mouse is locked."> +<ul> + <li>Lock mouse: left click in either of the two boxes; or right click in + either of the boxes to ensure that it is focused and then press Enter key. + </li> + <li>Unlock mouse: lose focus, press Esc key, or right click.</li> +</ul> +<object id="plugin" type="application/x-ppapi-example-mouse-lock" + width="300" height="300" border="2px"></object> +<div></div> +<object id="plugin" type="application/x-ppapi-example-mouse-lock" + width="300" height="300" border="2px"></object> +</body> +</html> |