Virtual pageviews is in fact the way to go with this. With a virtual pageview setup, your form tag would look something like this:
<form action="x.something" onsubmit="_gaq.push(['_trackPageview', '/submitted-form/']);">
That way, when the form is submitted, it will track a pageview of '/submitted-form/'. You can then create your goal looking for pageviews of that URL.
The main potential obstacle with this approach is form validation. If your form uses JavaScript for validation, then you need to integrate the virtual pageview code into the validation code, which can get complicated. If your form uses server side validation, this method also isn't great - because if the user submits the form and it returns an error, the virtual pageview will still be triggered, incorrectly converting the goal.
</form>