Last updated: 12 Jan 21 18:02:33 (UTC)

Keyboard driven Twining (tutorial) : twinegames

I wanted to be able to hit “Enter” to trigger buttons on every passage, but I also did NOT want to have to put an id or class on every button (because there’s one in each of 40 passages). So I used the tutorial below and here to FINALLY land on this javascript solution:

(function(){
    $(document).keyup(function(e){
        if(e.key == 'Enter'){
            $('button').trigger("click");
        }
    });
}());
(function(){
    $(document).keyup(function(e){
        if(e.key == 'Enter'){
            $('button').trigger("click");
        }
    });
}());

Keyboard driven Twining (tutorial)

Continuing my dedication to figuring things out and then explaining them, I bring you:

Edit: I wrote a script that automates a lot of this process and put it in the comments.

KEYBOARD DRIVEN TWINING

You can find the last tutorial post I made here.

Without further ado, you’ll need a few things:

*It’s best if you use SugarCube 2. The code below will be in SugarCube syntax. You will almost certainly not be able to hack this into Harlowe.

  • Twine 1’s multiple script passages might make organization easier.

Let’s start with the easy part. Open a passage and make a link, then wrap it in a span:

::a passage [[Click me, or press space|next passage]] Now, in your story’s JavaScript, type: (function(){     (document).keyup(function(e){         if(e.keyCode == 32){             KaTeX parse error: Expected '}', got 'EOF' at end of input: …){             (‘#spaceAct a’).trigger(“click”);         }     }); }()); Fire it up in test mode, and hit space. Multiple Links

Let’s creat a bunch of links and map them to the number keys. Then we’ll make a button that refreshes the page and map that to a the spacebar.

::a passage [[move to the next passage|next passage]]

<<linkreplace “replace some stuff”>><<timed 100ms t8n>>REPLACED<><>

<<link “clickity click”>><>UI.alert(“YAY”)<><>

<<button “Refresh”>><>State.display(passage())<><>

Now, in your scripts: (function(){     (document).keyup(function(e){         if(e.keyCode == 49){             KaTeX parse error: Expected '}', got 'EOF' at end of input: …){             (‘#oneAct a’).trigger(“click”);         }     }); }());

(function(){     (document).keyup(function(e){         if(e.keyCode == 50){             KaTeX parse error: Expected '}', got 'EOF' at end of input: …){             (‘#twoAct a’).trigger(“click”);         }     }); }());

(function(){     (document).keyup(function(e){         if(e.keyCode == 51){             KaTeX parse error: Expected '}', got 'EOF' at end of input: …){             (‘#threeAct a’).trigger(“click”);         }     }); }());

(function(){     (document).keyup(function(e){         if(e.keyCode == 32){             KaTeX parse error: Expected '}', got 'EOF' at end of input: …){             (‘#spaceAct button’).trigger(“click”);             //notice it’s $(‘id button’) instead of $(‘id a’)         }     }); }()); So what else can we do?

Let’s say you want to make a key press open a menu that isn’t on the page, such as a character menu. We’ll set something up so that the key press opens the same passage every time.

In this case, we leave the passages alone and go straight for the scripts: function(){     $(document).keyup(function(e){         if(e.keyCode == 67 && State.variables.inMenu == 0){             State.variables.return = passage();             State.variables.inMenu = 1;             State.display(‘charmenu’);         }     }); }());

In the above example, I’m using the variable $inMenu to see if the player is in a menu. If they are, the StoryMenu passage is emptied and this key press won’t work: this prevents the player from getting stuck inside the menus.

The variable return stores the passage the player came from (as in [[Return to Game|returnstoresthepassagetheplayercamefrom(asin[[ReturntoGamereturn stores the passage the player came from (as in [[Return to Game|return]]).

You’ll want to change these variables over to whatever you’re using to keep players from getting stuck in the menus.

How it all works, step-by-step: Let’s look at the code one more time. (function(){     $(document).keyup(function(e){ This code sets up the event listener. It should pretty much always be the same.         if(e.keyCode == 32){

This code identifies the key pressed. If it matches one of the code chunks, everything inside the if(){} is executed. You can look up keycodes here.

$(‘#twoAct a’).trigger(“click”);

This identifies the link (a) or button (button) you want to simulate a click on. The format is $(‘id element’), where id is the selector that you tell the code to search through (classes, as in “.class” also work, but are a bad idea–you could trigger multiple links), and element is what you want to click on (an anchor or a button).

And then we just need a bunch of closing statements:         }     }); }()); Let me know if you have any questions.

If this kind of stuff is helpful to you guys, let me know and I’ll keep it going. There’s a lot of Twine guides out there, but I feel like 90% are beginner’s guides (and stone-cold-stupid easy) and the rest are just pure JavaScript brute-forcing; I feel like we’re missing a nice middle-ground, and that’s something I feel like I can help out with.

PS: It’s possible I made a transcription error. If I did, PM me and I’ll fix it.

Edit: Formatting.

5 comments

90% Upvoted This thread is archived New comments cannot be posted and votes cannot be cast Sort by level 1

Here’s a script for you guys to make things super easy, if anyone wants it (goes in a script-tagged passage in Twine 1 or “Story JavaScript” in Twine 2):

!function(){(document).keyup(function(t){49==t.keyCode&&(KaTeX parse error: Expected '}', got '&' at position 43: …){49==t.keyCode&̲&((“#oneAct a”).trigger(“click”),("#oneAct button").trigger("click")),50==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲oneAct button")…(“#twoAct a”).trigger(“click”),("#twoAct button").trigger("click")),51==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲twoAct button")…(“#threeAct a”).trigger(“click”),("#threeAct button").trigger("click")),52==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲threeAct button…(“#fourAct a”).trigger(“click”),("#fourAct button").trigger("click")),53==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲fourAct button"…(“#fiveAct a”).trigger(“click”),("#fiveAct button").trigger("click")),54==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲fiveAct button"…(“#sixAct a”).trigger(“click”),("#sixAct button").trigger("click")),55==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲sixAct button")…(“#sevenAct a”).trigger(“click”),("#sevenAct button").trigger("click")),56==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲sevenAct button…(“#eightAct a”).trigger(“click”),("#eightAct button").trigger("click")),57==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲eightAct button…(“#nineAct a”).trigger(“click”),("#nineAct button").trigger("click")),48==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲nineAct button"…(“#zeroAct a”).trigger(“click”),("#zeroAct button").trigger("click")),9==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲zeroAct button"…(“#tabAct a”).trigger(“click”),("#tabAct button").trigger("click")),32==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲tabAct button")…(“#spaceAct a”).trigger(“click”),("#spaceAct button").trigger("click")),17==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲spaceAct button…(“#ctrlAct a”).trigger(“click”),("#ctrlAct button").trigger("click")),8==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲ctrlAct button"…(“#bkspAct a”).trigger(“click”),("#bkspAct button").trigger("click")),27==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲bkspAct button"…(“#escAct a”).trigger(“click”),("#escAct button").trigger("click")),46==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲escAct button")…(“#delAct a”).trigger(“click”),("#delAct button").trigger("click")),13==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲delAct button")…(“#enterAct a”).trigger(“click”),("#enterAct button").trigger("click")),18==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲enterAct button…(“#altAct a”).trigger(“click”),("#altAct button").trigger("click")),81==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲altAct button")…(“#qKeyAct a”).trigger(“click”),("#qKeyAct button").trigger("click")),87==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲qKeyAct button"…(“#wKeyAct a”).trigger(“click”),("#wKeyAct button").trigger("click")),69==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲wKeyAct button"…(“#eKeyAct a”).trigger(“click”),("#eKeyAct button").trigger("click")),82==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲eKeyAct button"…(“#rKeyAct a”).trigger(“click”),("#rKeyAct button").trigger("click")),84==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲rKeyAct button"…(“#tKeyAct a”).trigger(“click”),("#tKeyAct button").trigger("click")),89==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲tKeyAct button"…(“#yKeyAct a”).trigger(“click”),("#yKeyAct button").trigger("click")),85==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲yKeyAct button"…(“#uKeyAct a”).trigger(“click”),("#uKeyAct button").trigger("click")),73==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲uKeyAct button"…(“#iKeyAct a”).trigger(“click”),("#iKeyAct button").trigger("click")),79==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲iKeyAct button"…(“#oKeyAct a”).trigger(“click”),("#oKeyAct button").trigger("click")),80==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲oKeyAct button"…(“#pKeyAct a”).trigger(“click”),("#pKeyAct button").trigger("click")),65==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲pKeyAct button"…(“#aKeyAct a”).trigger(“click”),("#aKeyAct button").trigger("click")),83==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲aKeyAct button"…(“#sKeyAct a”).trigger(“click”),("#sKeyAct button").trigger("click")),68==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲sKeyAct button"…(“#dKeyAct a”).trigger(“click”),("#dKeyAct button").trigger("click")),70==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲dKeyAct button"…(“#fKeyAct a”).trigger(“click”),("#fKeyAct button").trigger("click")),71==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲fKeyAct button"…(“#gKeyAct a”).trigger(“click”),("#gKeyAct button").trigger("click")),72==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲gKeyAct button"…(“#hKeyAct a”).trigger(“click”),("#hKeyAct button").trigger("click")),74==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲hKeyAct button"…(“#jKeyAct a”).trigger(“click”),("#jKeyAct button").trigger("click")),75==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲jKeyAct button"…(“#kKeyAct a”).trigger(“click”),("#kKeyAct button").trigger("click")),76==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲kKeyAct button"…(“#lKeyAct a”).trigger(“click”),("#lKeyAct button").trigger("click")),90==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲lKeyAct button"…(“#zKeyAct a”).trigger(“click”),("#zKeyAct button").trigger("click")),88==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲zKeyAct button"…(“#xKeyAct a”).trigger(“click”),("#xKeyAct button").trigger("click")),67==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲xKeyAct button"…(“#cKeyAct a”).trigger(“click”),("#cKeyAct button").trigger("click")),86==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲cKeyAct button"…(“#vKeyAct a”).trigger(“click”),("#vKeyAct button").trigger("click")),66==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲vKeyAct button"…(“#bKeyAct a”).trigger(“click”),("#bKeyAct button").trigger("click")),78==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲bKeyAct button"…(“#nKeyAct a”).trigger(“click”),("#nKeyAct button").trigger("click")),77==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲nKeyAct button"…(“#mKeyAct a”).trigger(“click”),("#mKeyAct button").trigger("click")),112==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲mKeyAct button"…(“#f1KeyAct a”).trigger(“click”),("#f1KeyAct button").trigger("click")),113==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f1KeyAct button…(“#f2KeyAct a”).trigger(“click”),("#f2KeyAct button").trigger("click")),114==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f2KeyAct button…(“#f3KeyAct a”).trigger(“click”),("#f3KeyAct button").trigger("click")),115==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f3KeyAct button…(“#f4KeyAct a”).trigger(“click”),("#f4KeyAct button").trigger("click")),116==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f4KeyAct button…(“#f5KeyAct a”).trigger(“click”),("#f5KeyAct button").trigger("click")),117==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f5KeyAct button…(“#f6KeyAct a”).trigger(“click”),("#f6KeyAct button").trigger("click")),118==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f6KeyAct button…(“#f7KeyAct a”).trigger(“click”),("#f7KeyAct button").trigger("click")),119==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f7KeyAct button…(“#f8KeyAct a”).trigger(“click”),("#f8KeyAct button").trigger("click")),120==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f8KeyAct button…(“#f9KeyAct a”).trigger(“click”),("#f9KeyAct button").trigger("click")),121==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f9KeyAct button…(“#f10KeyAct a”).trigger(“click”),("#f10KeyAct button").trigger("click")),122==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f10KeyAct butto…(“#f11KeyAct a”).trigger(“click”),("#f11KeyAct button").trigger("click")),123==t.keyCode&&(KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲f11KeyAct butto…(“#f12KeyAct a”).trigger(“click”),$(“#f12KeyAct button”).trigger(“click”))})}();

To use it, add spans around any link or button element you want to be controllable from the keyboard. You should only have one span of each kind per passage. The id you need is:

For number keys: the number written out + “Act” Examples: [[link/button code]]

[[link/button code]]

[[link/button code]]

[[link/button code]] For letter keys: the letter (lower case) + “KeyAct” Examples: [[link/button code]]

[[link/button code]]

[[link/button code]]

[[link/button code]]

For function keys (may not work great on all browsers!): the name of the key (lower case) + “KeyAct”

Examples: [[link/button code]]

[[link/button code]]

[[link/button code]]

[[link/button code]] For other keys the name of the key, or an abbreviation + “Act” All such keys are listed below: [[link/button code]]/%backspace%/

[[link/button code]]/%delete%/

[[link/button code]]/%space%/

[[link/button code]]/%tab%/

[[link/button code]]/%control%/

[[link/button code]]/%alt%/

[[link/button code]]/%enter%/

[[link/button code]]/%escape%/

No other keys are supported. The code also doesn’t account for anything like holding shift or ctrl and pressing a button.

EDIT

Here’s a macro that further automates everything. You still need the script above, though:

Macro.add(‘linkkey’, {      tags : null,     handler : function () {

var $wrapper = $(document.createElement(‘span’));         var link = ‘link’;         var content = this.payload[0].contents;

if (this.args.length < 2 || this.args.length > 3) {             return this.error(‘incorrect number of arguments’);         } else {             var text = this.args[0];             var key = this.args[1];         }

if (this.args.length === 3) {             if (this.args.includes(‘btn’)) {                 link = ‘button’;             } else if (this.args.includes(‘rpl’)) {                 link = ‘linkreplace’;             } else if (this.args.includes(‘app’)) {                 link = ‘linkappend’;             } else if (this.args.includes(‘pre’)) {                 link = ‘linkprepend’;             } else {                 link = ‘link’;             }         }

$wrapper

.wiki(‘<<’ + link + ’ “’ + text + '”>>’ + content + ‘<</’ + link + ‘>>’)

.attr(‘id’, key)             .appendTo(this.output);         } }); Usage: <<linkkey ‘link text’ ‘keyID’ type>>…<>

  • link text: text of the link
  • keyID: the span id used in the link key script, as described above
  • type: optional keyword (can be: btn (makes a button), rpl (makes a <>), app (makes a <>), or pre (makes a <>)). If left blank, defaults to a normal <>.

IMPORTANT NOTES:

(1) This macro does not accept passages as an argument; you’ll have to use <>:

<<linkkey ‘link text’ ‘spaceAct’>><<goto ‘passage’>><>

(2) This macro does not accept wiki link syntax (e.g. <<linkkey [[text|passage]] ‘oneAct’>> will not work).

1 level 2 ChapelR, you are my lord and saviour. 1

Continue this thread