diff --git a/src/containers/stage.jsx b/src/containers/stage.jsx
index d9ab05f12966d701d898142b9f7a5a4855af9d15..8399855c195d64e2b0d664b417d15e29b011f6f0 100644
--- a/src/containers/stage.jsx
+++ b/src/containers/stage.jsx
@@ -4,6 +4,7 @@ import React from 'react';
 import Renderer from 'scratch-render';
 import AudioEngine from 'scratch-audio';
 import VM from 'scratch-vm';
+import {getEventXY} from '../lib/touch-utils';
 
 import StageComponent from '../components/stage/stage.jsx';
 
@@ -50,12 +51,18 @@ class Stage extends React.Component {
     attachMouseEvents (canvas) {
         document.addEventListener('mousemove', this.onMouseMove);
         document.addEventListener('mouseup', this.onMouseUp);
+        document.addEventListener('touchmove', this.onMouseMove);
+        document.addEventListener('touchend', this.onMouseUp);
         canvas.addEventListener('mousedown', this.onMouseDown);
+        canvas.addEventListener('touchstart', this.onMouseDown);
     }
     detachMouseEvents (canvas) {
         document.removeEventListener('mousemove', this.onMouseMove);
         document.removeEventListener('mouseup', this.onMouseUp);
+        document.removeEventListener('touchmove', this.onMouseMove);
+        document.removeEventListener('touchend', this.onMouseEnd);
         canvas.removeEventListener('mousedown', this.onMouseDown);
+        canvas.removeEventListener('touchstart', this.onMouseDown);
     }
     attachRectEvents () {
         window.addEventListener('resize', this.updateRect);
@@ -76,8 +83,9 @@ class Stage extends React.Component {
         ];
     }
     handleDoubleClick (e) {
+        const {x, y} = getEventXY(e);
         // Set editing target from cursor position, if clicking on a sprite.
-        const mousePosition = [e.clientX - this.rect.left, e.clientY - this.rect.top];
+        const mousePosition = [x - this.rect.left, y - this.rect.top];
         const drawableId = this.renderer.pick(mousePosition[0], mousePosition[1]);
         if (drawableId === null) return;
         const targetId = this.props.vm.getTargetIdForDrawableId(drawableId);
@@ -85,7 +93,8 @@ class Stage extends React.Component {
         this.props.vm.setEditingTarget(targetId);
     }
     onMouseMove (e) {
-        const mousePosition = [e.clientX - this.rect.left, e.clientY - this.rect.top];
+        const {x, y} = getEventXY(e);
+        const mousePosition = [x - this.rect.left, y - this.rect.top];
         if (this.state.mouseDownTimeoutId !== null) {
             this.cancelMouseDownTimeout();
             if (this.state.mouseDown && !this.state.isDragging) {
@@ -109,6 +118,7 @@ class Stage extends React.Component {
         this.props.vm.postIOData('mouse', coordinates);
     }
     onMouseUp (e) {
+        const {x, y} = getEventXY(e);
         this.cancelMouseDownTimeout();
         this.setState({
             mouseDown: false,
@@ -119,8 +129,8 @@ class Stage extends React.Component {
         } else {
             const data = {
                 isDown: false,
-                x: e.clientX - this.rect.left,
-                y: e.clientY - this.rect.top,
+                x: x - this.rect.left,
+                y: y - this.rect.top,
                 canvasWidth: this.rect.width,
                 canvasHeight: this.rect.height
             };
@@ -129,7 +139,8 @@ class Stage extends React.Component {
     }
     onMouseDown (e) {
         this.updateRect();
-        const mousePosition = [e.clientX - this.rect.left, e.clientY - this.rect.top];
+        const {x, y} = getEventXY(e);
+        const mousePosition = [x - this.rect.left, y - this.rect.top];
         this.setState({
             mouseDown: true,
             mouseDownPosition: mousePosition,
@@ -146,7 +157,9 @@ class Stage extends React.Component {
             canvasHeight: this.rect.height
         };
         this.props.vm.postIOData('mouse', data);
-        e.preventDefault();
+        if (e.preventDefault) {
+            e.preventDefault();
+        }
     }
     cancelMouseDownTimeout () {
         if (this.state.mouseDownTimeoutId !== null) {