 diff --git a/src/library_glfw.js b/src/library_glfw.js
-index dfa4896c4..503ac68a8 100644
+index dfa4896c4..73db4cf7c 100644
 --- a/src/library_glfw.js
 +++ b/src/library_glfw.js
 @@ -13,7 +13,6 @@

     },
 
+    onGamepadConnected: function(event) {
+      if (!GLFW.active.joystickFunc) return;
+
+      // HTML5 Gamepad API reuses indexes
+      // glfw joystick API spreads them out
+      // http://www.glfw.org/docs/latest/input_guide.html#joystick
+      // "Once a joystick is detected, it keeps its assigned index until it is disconnected,
+      // so as joysticks are connected and disconnected, they will become spread out."
+      var joy = GLFW.active.joyLast++;
+      GLFW.active.joys[joy] = {
+        index: event.gamepad.index,
+        id: allocate(intArrayFromString(event.gamepad.id), 'i8', ALLOC_NORMAL),
+        buttons: allocate(new Array(event.gamepad.buttons.length), 'float', ALLOC_NORMAL),
+        axes: allocate(event.gamepad.axes, 'float', ALLOC_NORMAL)
+      };
+      GLFW.active.index2joy[event.gamepad.index] = joy;
+      Module['dynCall_vii'](GLFW.active.joystickFunc, joy, 0x00040001); // GLFW_CONNECTED
+    },
+
+    onGamepadDisconnected: function(event) {
+      if (!GLFW.active.joystickFunc) return;
+
+      var joy = GLFW.active.index2joy[event.gamepad.index];
+
+      Module['dynCall_vii'](GLFW.active.joystickFunc, joy, 0x00040002); // GLFW_DISCONNECTED
+
+      // TODO: free memory .axes, .buttons
+
+      delete GLFW.active.index2joy[event.gamepad.index];
+      delete GLFW.active.joys[joy];
+    },
+
     onKeydown: function(event) {

       if (!GLFW.active.keyFunc) return;
 
 #if USE_GLFW == 2
@@ -375,12 +378,20 @@ var LibraryGLFW = {
 
 #if USE_GLFW == 3
       if (repeat) status = 2; // GLFW_REPEAT
