 +      var count = event.dataTransfer.files.length;
 +
 +      // Read and save the files to emscripten's FS
-+      // TODO: lazily load?
 +      var written = 0;
++      var drop_dir = '.glfw_dropped_files';
++      FS.createPath('/', drop_dir);
++
++      function save(file) {
++        var path = '/' + drop_dir + '/' + file.name.replace(/\//g, '_');
++        var reader = new FileReader();
++        reader.onloadend = function(e) {
++          if (reader.readyState != 2) { // not DONE
++            ++written;
++            console.log('failed to read dropped file: '+file.name+': '+reader.error);
++            return;
++          }
++
++          var data = e.target.result;
++          FS.writeFile(path, new Uint8Array(data), { encoding: 'binary' });
++          if (++written === count) {
++            Module['dynCall_viii'](GLFW.active.dropFunc, GLFW.active.id, count, filenames);
++
++            for (var i = 0; i < filenamesArray.length; ++i) {
++              _free(filenamesArray[i]);
++            }
++            _free(filenames);
++          }
++        };
++        reader.readAsArrayBuffer(file);
++
++        var filename = allocate(intArrayFromString(path), 'i8', ALLOC_NORMAL);
++        filenamesArray.push(filename);
++        setValue(filenames + i*4, filename, 'i8*');
++      }
++
 +      for (var i = 0; i < count; ++i) {
-+        (function(file) {
-+          var reader = new FileReader();
-+          reader.onload = function(e) {
-+            var data = e.target.result;
-+            var path = file.name; // TODO: to a new directory?
-+            FS.writeFile(path, new Uint8Array(data), { encoding: 'binary' });
-+            //console.log('wrote '+path+', size '+data.byteLength+', count '+written+' of '+count);
-+            if (++written === count) {
-+              console.log('calling callback');
-+              Module['dynCall_viii'](GLFW.active.dropFunc, GLFW.active.id, count, filenames);
-+
-+              for (var i = 0; i < filenamesArray.length; ++i) _free(filenamesArray[i]);
-+              _free(filenames);
-+            }
-+          };
-+          reader.readAsArrayBuffer(file);
-+
-+          var filename = allocate(intArrayFromString(file.name), 'i8', ALLOC_NORMAL);
-+          filenamesArray.push(filename);
-+          setValue(filenames + i*4, filename, 'i8*');
-+        })(event.dataTransfer.files[i]);
++        save(event.dataTransfer.files[i]);
 +      }
 +
 +      return false;
 +    },
 +
 +    onDragover: function(event) {
-+      if (!GLFW.active.dropFunc) return;
++      if (!GLFW.active || !GLFW.active.dropFunc) return;
 +
 +      event.preventDefault();
-+      return false;
-+    },
-+
-+    onDragend: function(event) {
-+      if (!GLFW.active.dropFunc) return;
-+
 +      return false;
 +    },
 +
      setWindowSizeCallback: function(winid, cbfun) {
        var win = GLFW.WindowFromId(winid);
        if (!win) return;
-@@ -941,9 +1082,12 @@ var LibraryGLFW = {
+@@ -941,9 +1087,12 @@ var LibraryGLFW = {
      GLFW.windows = new Array()
      GLFW.active = null;
  

diff --git a/src/library_glfw.js b/src/library_glfw.js
index dfa4896c4..98368a799 100644
--- a/src/library_glfw.js
+++ b/src/library_glfw.js
@@ -13,7 +13,6 @@

+
+  glfwGetJoystickButtons: function(joy, count) {
+    GLFW.refreshJoysticks();
 
-  glfwGetJoystickAxes: function(joy, count) { throw "glfwGetJoystickAxes is not implemented."; },
+    var state = GLFW.joys[joy];
+    if (!state || !state.buttons) {
+      setValue(count, 0, 'i32');
+      return;
+    }
 
-  glfwGetJoystickButtons: function(joy, count) { throw "glfwGetJoystickButtons is not implemented."; },
+    setValue(count, state.buttonsCount, 'i32');
+    return state.buttons;
+  },
 
-  glfwGetJoystickName: function(joy) { throw "glfwGetJoystickName is not implemented."; },
+  glfwGetJoystickName: function(joy) {
+    if (GLFW.joys[joy]) {
+      return GLFW.joys[joy].id;
