diff --git a/remoting/client/input_handler.cc b/remoting/client/input_handler.cc
index 7b48d89d94f61..48beddedd5234 100644
--- a/remoting/client/input_handler.cc
+++ b/remoting/client/input_handler.cc
@@ -62,6 +62,16 @@ void InputHandler::SendMouseButtonEvent(bool button_down,
   }
 }
 
+void InputHandler::SendMouseWheelEvent(int dx, int dy) {
+  protocol::InputStub* stub = connection_->input_stub();
+  if (stub) {
+    MouseEvent event;
+    event.set_wheel_offset_x(dx);
+    event.set_wheel_offset_y(dy);
+    stub->InjectMouseEvent(event);
+  }
+}
+
 void InputHandler::ReleaseAllKeys() {
   std::set<int> pressed_keys_copy = pressed_keys_;
   std::set<int>::iterator i;
diff --git a/remoting/client/input_handler.h b/remoting/client/input_handler.h
index f65ede15b6e21..c1c783b77e51c 100644
--- a/remoting/client/input_handler.h
+++ b/remoting/client/input_handler.h
@@ -36,6 +36,7 @@ class InputHandler {
   void SendMouseMoveEvent(int x, int y);
   void SendMouseButtonEvent(bool down,
                             protocol::MouseEvent::MouseButton button);
+  void SendMouseWheelEvent(int dx, int dy);
 
   ClientContext* context_;
   protocol::ConnectionToHost* connection_;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 6a32a0bcf6392..7eb70a90d674b 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -258,6 +258,11 @@ bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) {
       return true;
     }
 
+    case PP_INPUTEVENT_TYPE_WHEEL: {
+      pih->HandleMouseWheelEvent(pp::WheelInputEvent(event));
+      return true;
+    }
+
     case PP_INPUTEVENT_TYPE_CONTEXTMENU: {
       // We need to return true here or else we'll get a local (plugin) context
       // menu instead of the mouseup event for the right click.
diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc
index e07ff43cd7571..1fe6f6e543636 100644
--- a/remoting/client/plugin/pepper_input_handler.cc
+++ b/remoting/client/plugin/pepper_input_handler.cc
@@ -10,16 +10,15 @@
 
 namespace remoting {
 
-using pp::KeyboardInputEvent;
-using pp::MouseInputEvent;
-using protocol::KeyEvent;
 using protocol::MouseEvent;
 
 PepperInputHandler::PepperInputHandler(ClientContext* context,
                                        protocol::ConnectionToHost* connection,
                                        PepperViewProxy* view)
     : InputHandler(context, connection, view),
-      pepper_view_(view) {
+      pepper_view_(view),
+      wheel_ticks_x_(0),
+      wheel_ticks_y_(0) {
 }
 
 PepperInputHandler::~PepperInputHandler() {
@@ -78,4 +77,18 @@ void PepperInputHandler::HandleMouseButtonEvent(
   }
 }
 
+void PepperInputHandler::HandleMouseWheelEvent(
+    const pp::WheelInputEvent& event) {
+  pp::FloatPoint ticks = event.GetTicks();
+  wheel_ticks_x_ += ticks.x();
+  wheel_ticks_y_ += ticks.y();
+  int ticks_x = static_cast<int>(wheel_ticks_x_);
+  int ticks_y = static_cast<int>(wheel_ticks_y_);
+  if (ticks_x != 0 || ticks_y != 0) {
+    wheel_ticks_x_ -= ticks_x;
+    wheel_ticks_y_ -= ticks_y;
+    SendMouseWheelEvent(ticks_x, ticks_y);
+  }
+}
+
 }  // namespace remoting
diff --git a/remoting/client/plugin/pepper_input_handler.h b/remoting/client/plugin/pepper_input_handler.h
index 7c1c0a908fd70..de87a4885c140 100644
--- a/remoting/client/plugin/pepper_input_handler.h
+++ b/remoting/client/plugin/pepper_input_handler.h
@@ -13,11 +13,6 @@ class MouseInputEvent;
 class WheelInputEvent;
 }
 
-namespace pp {
-class KeyboardInputEvent;
-class MouseInputEvent;
-}  // namespace pp
-
 namespace remoting {
 
 class PepperViewProxy;
@@ -37,10 +32,14 @@ class PepperInputHandler : public InputHandler {
   void HandleMouseMoveEvent(const pp::MouseInputEvent& event);
   void HandleMouseButtonEvent(bool button_down,
                               const pp::MouseInputEvent& event);
+  void HandleMouseWheelEvent(const pp::WheelInputEvent& event);
 
  private:
   PepperViewProxy* pepper_view_;
 
+  float wheel_ticks_x_;
+  float wheel_ticks_y_;
+
   DISALLOW_COPY_AND_ASSIGN(PepperInputHandler);
 };
 
diff --git a/remoting/host/event_executor_linux.cc b/remoting/host/event_executor_linux.cc
index 2321c5c0ec3dd..2eaf83e3ae205 100644
--- a/remoting/host/event_executor_linux.cc
+++ b/remoting/host/event_executor_linux.cc
@@ -36,6 +36,8 @@ class EventExecutorLinux : public EventExecutor {
   virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE;
 
  private:
+  void InjectScrollWheelClicks(int button, int count);
+
   MessageLoop* message_loop_;
   Capturer* capturer_;
 
@@ -68,6 +70,16 @@ int MouseButtonToX11ButtonNumber(MouseEvent::MouseButton button) {
   }
 }
 
+int ScrollWheelToX11ButtonNumber(int dx, int dy) {
+  // Horizontal scroll wheel.
+  if (dx != 0)
+    return (dx > 0 ? 6 : 7);
+
+  // Positive y-values are wheel scroll-up events (button 4), negative y-values
+  // are wheel scroll-down events (button 5).
+  return (dy > 0 ? 4 : 5);
+}
+
 // Hard-coded mapping from Virtual Key codes to X11 KeySyms.
 // This mapping is only valid if both client and host are using a
 // US English keyboard layout.
@@ -309,6 +321,15 @@ void EventExecutorLinux::InjectKeyEvent(const KeyEvent& event) {
   XFlush(display_);
 }
 
+void EventExecutorLinux::InjectScrollWheelClicks(int button, int count) {
+  for (int i = 0; i < count; i++) {
+    // Generate a button-down and a button-up to simulate a wheel click.
+    XTestFakeButtonEvent(display_, button, true, CurrentTime);
+    XTestFakeButtonEvent(display_, button, false, CurrentTime);
+  }
+  XFlush(display_);
+}
+
 void EventExecutorLinux::InjectMouseEvent(const MouseEvent& event) {
   if (MessageLoop::current() != message_loop_) {
     message_loop_->PostTask(
@@ -339,8 +360,7 @@ void EventExecutorLinux::InjectMouseEvent(const MouseEvent& event) {
     int button_number = MouseButtonToX11ButtonNumber(event.button());
 
     if (button_number < 0) {
-      LOG(WARNING) << "Ignoring unknown button type: "
-                   << event.button();
+      LOG(WARNING) << "Ignoring unknown button type: " << event.button();
       return;
     }
 
@@ -353,8 +373,15 @@ void EventExecutorLinux::InjectMouseEvent(const MouseEvent& event) {
     XFlush(display_);
   }
 
-  if (event.has_wheel_offset_x() && event.has_wheel_offset_y()) {
-    NOTIMPLEMENTED() << "No scroll wheel support yet.";
+  if (event.has_wheel_offset_y() && event.wheel_offset_y() != 0) {
+    int dy = event.wheel_offset_y();
+    InjectScrollWheelClicks(ScrollWheelToX11ButtonNumber(0, dy),
+                            (dy > 0) ? dy : -dy);
+  }
+  if (event.has_wheel_offset_x() && event.wheel_offset_x() != 0) {
+    int dx = event.wheel_offset_x();
+    InjectScrollWheelClicks(ScrollWheelToX11ButtonNumber(dx, 0),
+                            (dx > 0) ? dx : -dx);
   }
 }
 
diff --git a/remoting/host/event_executor_win.cc b/remoting/host/event_executor_win.cc
index 7e3d8013fb9a0..b1f58427f4c01 100644
--- a/remoting/host/event_executor_win.cc
+++ b/remoting/host/event_executor_win.cc
@@ -127,12 +127,12 @@ void EventExecutorWin::HandleMouse(const MouseEvent& event) {
     int dy = event.wheel_offset_y();
 
     if (dx != 0) {
-      wheel.mi.mouseData = dx;
+      wheel.mi.mouseData = dx * WHEEL_DELTA;
       wheel.mi.dwFlags = MOUSEEVENTF_HWHEEL;
       SendInput(1, &wheel, sizeof(INPUT));
     }
     if (dy != 0) {
-      wheel.mi.mouseData = dy;
+      wheel.mi.mouseData = dy * WHEEL_DELTA;
       wheel.mi.dwFlags = MOUSEEVENTF_WHEEL;
       SendInput(1, &wheel, sizeof(INPUT));
     }
diff --git a/remoting/proto/event.proto b/remoting/proto/event.proto
index 2098e70861d5f..a5c03434a02d5 100644
--- a/remoting/proto/event.proto
+++ b/remoting/proto/event.proto
@@ -11,7 +11,6 @@ option optimize_for = LITE_RUNTIME;
 package remoting.protocol;
 
 // Defines a keyboard event.
-// NEXT ID: 3
 message KeyEvent {
   // The POSIX key code.
   required int32 keycode = 1;
@@ -34,6 +33,9 @@ message MouseEvent {
   optional int32 y = 2;
 
   // Mouse wheel information.
+  // These values encode the number of wheel 'ticks' (sometimes called
+  // 'clicks' although 'ticks' is the most common cross-platform term).
+  // Additional fields may be added later to support high-resolution devices.
   optional int32 wheel_offset_x = 3;
   optional int32 wheel_offset_y = 4;