Link macro with keyboard event

I made keyboard macro to use hot key for some menus

Macro.add('key', {
	tags : null,
	handler: function() {
		var input = this.args[0];
		var linktext = this.args[1];
		var linkaction = this.payload[0].contents;
		var result = '<span id='+input+'><<link '+linktext+'>>'+linkaction+'<</link>> ('+input+')</span>';
		var check = input.toUpperCase()
		if (input == '←'){check = 'BACKSPACE'}
		if (input == '↵'){check = 'ENTER'}
		if (input.toUpperCase() == 'ESC'){check = 'ESCAPE'}
		if (input.toUpperCase() == 'TAB'){check = 'TAB'}
		$(document).on('keyup', function (ev) {
			if (ev.key.toUpperCase() == check){
				$('#'+input+' .macro-link').click()

It works well but has two major issue

first, with link action like this,

/*$hk_Train = 'T'*/
<<key $hk_Train 'Train'>><<goto 'TrainScreen'>> <</key>>

after move passages several times with hot key, it get’s slower and slower. more than 10sec
but it’s ok with mouse click

second, I think its similar problem,

<span id='cal'><<key 'q' 'test'>><<set $test ++>><<replace '#cal'>><<include cal>><</replace>><</key>>

in passage ‘cal’, self replace macro, it appear once but work in duplicate with hot key.
with mouse click, it work once properly

any ideas?


It’s hard to tell exactly what’s going wrong, since I don’t know exactly how you’re using that code, but I strongly suspect the problem is that you’re accumulating a ton of different “keyup” events on the document. That would explain why it slows down the longer you use it.

Instead of $(document).on(), you might want to use $(document).one(), so that the event handler gets cleared after it’s used (see the .one() documentation).

Or, better yet, you could have one “keyup” event handler in the JavaScript, and use the macro to tag the link in a way that the event handler would automatically activate the tagged links.

If it helps, you might want to take a look at this keyboard navigation code for Twine/SugarCube to see how it can be done. (Click “Jump to Start” in the UI bar to see other sample code there.)

Hope that helps! :slight_smile:


I trying to make customisable hot key system and as you say, there’s many different keyup events with dynamic hot key, and hope same hot key work differently on different page.
I’m very lack of programming skill so I can’t understand second solution perfectly, but first one seems work well by now.
thank you for help!

ok I got it
this code will be better for more situation and maybe helpful for someone who trying to make hot key system


Macro.add('key', {
	tags : null,
	handler: function() {
		var input = this.args[0].toString();
		var linktext = this.args[1];
		var linkaction = this.payload[0].contents;
		var result = '<span id='+input.toUpperCase()+'><<link '+linktext+'>>'+linkaction+'<</link>> ('+input+')</span>';

$(document).on('keyup', function keyevent(ev) {
	var input = ev.key.toUpperCase();
	if (ev.key == 'Enter'){
		input = '↵'
		$('#ui-dialog-close').click() /*for dialog close*/
	if (ev.key == 'Backspace'){input = '←'}
	if (ev.key == 'Escape'){input = 'ESC'}
	if (ev.key == 'Tab'){input = 'TAB'}
	$('#'+input+' .macro-link').click()


Usage: <<key hotkey 'linktext'>> linkaction <</key>>

<<key 'Q' 'Main'>> <<goto 'MainPage'>> <</key>>
     is same with
[[Main|MainPage]] (Q)
     so it seems like
Main (Q)
    and it will work with hotkey 'Q' or even, lowercase 'q'

note: Custom Macros should be defined within either the Story Javascript area if you’re using the Twine 2.x application, or within a script tagged special passage if you’re using a TWEE compiler or the Twine 1.x application.

Looks much better now, though, like Greyelf said, it should be in your JavaScript section, so you won’t need the <<script>> macro there.

If you want, you can check to see if elements on the page exist using the .length property. For example, if ($('#'+input+' .macro-link').length > 0) would tell you if any elements fitting that description exist, which you could use to prevent any possible errors caused by trying to click an element that doesn’t exist.

Good work! :slight_smile: