7

I have an <input type="file" id="browse-button"/> file-browser input in my HTML.

I have another button with ID choose-file-button that, when clicked, calls document.getElementById("browse-button").click();. When this button is clicked, it correctly clicks #browse-button and the file dialog opens.

Now, I took code from this answer to intercept a Ctrl+O keypress and open my file dialog, so I have this:

$(window).bind('keydown', function(e)
{
    if (e.ctrlKey || e.metaKey)
    {
        switch (String.fromCharCode(e.which).toLowerCase())
        {
            case 's':
                e.preventDefault();
                // doesn't matter for this question
                return false;
            case 'o':
                e.preventDefault();
                document.getElementById("choose-file-button").click();
                return false;
        }
    }
    return true;
});

As you can see, when I intercept Ctrl+O I click on my #choose-file-button button, which calls document.getElementById("browse-button"); in its onclick handler. I have put a breakpoint in this click handler, and when I press Ctrl+O it does arrive at this breakpoint. However, the file dialog never shows up.

Through debugging, I found out that if I put an alert(...); after the #choose-file-button click() line, then the alert shows up and the normal page "Open File" dialog shows up (not my file dialog). If I do not have this alert, however, nothing shows up at all.

Is this a bug? How can I fix it and make my file dialog show up via the intercepted Ctrl+O?

Edit: I just tested in Chrome, and it works perfectly. However, it still does not work in Firefox.

Community
  • 1
  • 1
Jashaszun
  • 9,207
  • 3
  • 29
  • 57
  • Have you tried using JQuery to trigger your click with `$("#choose-file-button").click()` instead of using getElementById? – Osuwariboy Jun 26 '15 at 18:39
  • @Osuwariboy I have now, but it doesn't change anything. – Jashaszun Jun 26 '15 at 19:42
  • Your problem seems to be similar to this one: [override ctrl+s](http://stackoverflow.com/questions/14860759/cant-override-ctrls-in-firefox-using-jquery-hotkeys). Maybe you could try some of their suggestions? – Osuwariboy Jun 26 '15 at 19:57
  • @Osuwariboy Sure, but I don't want any alert at all, even a delayed one. – Jashaszun Jun 26 '15 at 20:03
  • is your caps lock on? <--- its a joke :) – Adam Buchanan Smith Jun 26 '15 at 22:59
  • There might be some useful information at this [SO](http://stackoverflow.com/a/6463467/1704725) answer to a similar post – Zach Ross-Clyne Jun 29 '15 at 11:30
  • Do you have an actual function for your click handler? Have you tried setting a breakpoint in it to check if it's being called at all? If it's not called, have you tried calling a dummy function that's not an event handler? If your dummy function's being called successfully, you can just move your treatment in there to see if it actually works. – Osuwariboy Jun 29 '15 at 13:33

4 Answers4

10

There's some browser security magic going on here. When using timeouts or intervals or any other methods I try, the code carries on as normal but the browser simply refuses to open a file upload dialog. This is probably deliberate, to stop malicious JS from trying to grab users' files without consent. However, if you bind to a click event on a link, it works perfectly using jQuery or regular JS.

Edit: As suspected, most browsers keep track of whether an event is trusted or not based on the type of event and whether it was created by the user or generated programmatically. Se this answer for the full details. As you can see, since keyboard events aren't in the list, they can never be trusted.

Test JSFiddle

<form action="#" method="post">
    <div>
        <input type="file" id="myfile" name="myfile" /> <a href="#" id="mylink" accesskey="o">Click me</a>
    </div>
</form>

$("#mylink").click(function () {
    $("#myfile").click();
});

$(window).bind('keydown', function (e) {
    if (e.ctrlKey || e.metaKey) {
        switch (String.fromCharCode(e.which).toLowerCase()) {
            case 'o':
                e.preventDefault();
                console.log("1a");

                $("#myfile").click();
                //alert("hello");

                console.log("1b");
                return false;
        }
    }
    return true;
});

I think there are only two options here, and they're both workarounds, not solutions.

  • One is to use a link to trigger the file upload dialog, and ask people to use ALT+SHIFT+O instead of CTRL+O (because I added an accesskey attribute to the link in the example).
  • The other alternative is to use one of the new HTML5 JavaScript APIs for drag-drop file uploading.

Addendum: I also tried using pure JavaScript in Firefox to grab a click event and check to see if it's trusted using the isTrusted property. For the clicks on the link, it returned true. However, attempting to store and re-use the event elsewhere doesn't work, because it's already been dispatched by the time you get a reference to it. Also, unsurprisingly, creating a new event and attempting to set isTrusted = true doesn't work either since it's read-only.

Community
  • 1
  • 1
BoffinBrain
  • 6,337
  • 6
  • 33
  • 59
  • @guest271314 Nice link! I had a very strong suspicion that the browser could tell the difference between genuine clicks and programmatic ones. – BoffinBrain Jul 03 '15 at 10:44
  • @BoffinbraiN Thank you for your detailed response, and sorry I wasn't here to ask questions/give answers/upvote earlier... I was out of town. Anyway, I may check out that HTML5 API, but if it looks too hard to use, I'll just stick with no keyboard shortcuts for file IO (since there are still buttons on the webpage that work perfectly fine). – Jashaszun Jul 06 '15 at 13:31
4

Browser map many Ctrl+ shortcuts to own commands, for instance CTRL+O to open a file (in firefox).

On the same time browser behave different when you try to override such shortcuts in javascript. Some browsers allow you to do so, some don't, and sometimes the default browser action may pop up together with the action of your javascript.

Here is another thread discussing this topic.

Probably the best you can do is to choose a different shortcut.

wero
  • 32,544
  • 3
  • 59
  • 84
4

You can try with Mousetrap library. It overrides the most problems that key capturing makes. Official website and complete refference:

https://craig.is/killing/mice

Good luck

Marcos Pérez Gude
  • 21,869
  • 4
  • 38
  • 69
  • Just to clarify here, the OP wanted to override the key combination Ctrl+O, not set up a click event, which is trivial to implement. – BoffinBrain Jul 03 '15 at 10:42
  • Mousetrap library is not to set a click event, is for the oppositte, is to avoid mouse usage, all with keyboard. – Marcos Pérez Gude Jul 03 '15 at 11:10
  • Aha... I see. A nice utility, but because of the issues mentioned in my answer, no JS library can get around the security precautions of the browser. I tried it with a Fiddle [here](http://jsfiddle.net/w26jo08u/). – BoffinBrain Jul 06 '15 at 13:48
1

You cannot do that in all browsers, as far as I am concern only IE allow it. I guess this is due to security issues, so that programmer are disabled to set the file name on the HTML File element automatically(without permission of client).

have a look on this link for more details:

In JavaScript can I make a "click" event fire programmatically for a file input element?

Show input file dialog on load?

Community
  • 1
  • 1
PHP Worm...
  • 4,109
  • 1
  • 25
  • 48