Quixe+GlkOte & City of Secrets v3 story on Android, keyboard

Reports ar that the keyboard flaps on/off in some stories when played from Google Chrome on an Android device, notably Emily Short’s City of Secrets v3. I’l looking into this today with the intention of seeing if we can come up with better JavaScript.

First off, I haven’t seen a play-online link for City of Secrets? the only thing I see is a CoS.zip file. Someone have it hosted elsewhere?

Open GitHub bug report: github.com/erkyrath/quixe/issues/32

If you want to play it online, you can play it using this hosted copy and the story query parameter:

github.com/chimara/Chimara/raw/ … /CoSv3.blb

E.g. eblong.com/zarf/glulx/quixe/quix … FCoSv3.blb

Thank you. I’m starting out with the Android SDK Emulator 7.1.1, with built-in Google Chrome browser version 55.0.2883.91 on that link. On the opening screen I go to the entry field of the “PRESS ANY KEY TO BEGIN” in soft-keyboard mode, and indeed it seems rather forceful about the keyboard input. If I choose the “hide keyboard” down-arrow (the “back button” of Android) the keyboard goes away and immediately comes back up.

Good news: Looking at the Glk interaction - running this story through RemGlk reveals that it is not timer-crazy with character input like the opening of some stories. It presents a simple Glk character prompt.

In contrast, the story “Best of Three” (same author, Emily Short) does a hyperfast timer loop at the opening prompt that burns CPU and causes a lot of grief with various layers. Best of Three hammers on the keyboard so hard in Google Chrome browser that even after I changed to another web page (back to Google’s home page) the keyboard was still going nuts for 20 seconds.

I tried commenting out all the places where glkote.js uses focus() with no success; the keyboard still pops right back up. The code is probably doing something somewhere that indirectly causes an element to become focused.

What I’m seeing so far: GlkOtel.js is going back and forth between two functions that seem of significance:

accept_inputset()  code link: [github.com/erkyrath/glkote/blob ... e.js#L1373](https://github.com/erkyrath/glkote/blob/master/glkote.js#L1373)
accept_inputcancel() code link: [github.com/erkyrath/glkote/blob ... e.js#L1348](https://github.com/erkyrath/glkote/blob/master/glkote.js#L1348)

If you add console logging to these two functions, you can see it going in/out multiple times. ( I’m using Chrome remote console so I can view it on my desktop. ) Glulx is doing nothing, if I run this through RemGlk - Glulx has stopped executing until some input is returned from the Glk layer - so Glulx itself has no role in this happening.

So far, I think a key factor is that when the keyboard pops up it resizes the window / HTML5 canvas area, and GlkOte is scaling the entire Glk window down so it fits on the window above the keyboard… that’s triggering these calls to accept_inputset()/accept_inputcancel() in the repaint… then the keyboard goes away, causing the window size to increase, another repaint, and it’s looping. That’s a key behavior change from desktop Chrome - when you use desktop Chrome - going in and out with the keyboard (changing to another app) is not going to cause the Chrome browser window to resize and a major repaint of the entire output.

I see that GlkOte already had some anti-jitter resize / debouncing logic

function evhan_doc_resize [github.com/erkyrath/glkote/blob ... e.js#L2297](https://github.com/erkyrath/glkote/blob/master/glkote.js#L2297)
function doc_resize_real resize [github.com/erkyrath/glkote/blob ... e.js#L2325](https://github.com/erkyrath/glkote/blob/master/glkote.js#L2325)

The code comments here explain the concern with rapid resizing of the window (desktop mouse resizing) that is in the same spirit of the issue we are seeing on the Android devices with the keyboard resizing the window. A timer is used to delay immediate resize, resize_timer. I found it helped to change the two places where delay_func is called with 0.20 to 3.0 - and you can more easily see the series of events taking place that cause the keyboard to hide and show.

To behave more like Apple devices, a transparent keyboard could be used - if you want to turn off the resizing / shrinking when the keyboard comes up, it is called in two significant places in GlkOte:

github.com/erkyrath/glkote/blob … te.js#L186
github.com/erkyrath/glkote/blob … te.js#L549 (the shrink is fine alone, no need to alter expand on the next line of code)

I commented out those two lines (186 and 549) and it seems to work fine on a full-screen Android Chrome. As a hotfix to get players up and running, I am currently thinking a URL parameter could be added that bypasses these two lines - giving the user at least a way to work around this behavior. With some stories, such as Dead Cities, on most Android devices there would not be enough screen space left to “resize” the canvas with the standard keyboard - literally the available height becomes so small that the story can no longer be played on that hardware in that screen orientation. It depends on the nature of the particular story if the keyboard is constantly being accessed or reading what is on-screen is more important.

Not in a position to test, at the moment, but would bypassing those two lines prevent orientation changes from working? That would be a big issue on mobile.

There is a way to address orientation alone in jQuery $(window).bind( ‘orientationchange’, function(e)) - but I was only suggesting exposing a URL param as a way to give the users some control (short of them editing the javascript themselves).

As far as more evolved fixes go, I would encourage thinking in terms of chewing bubblegum and walking at the same time :wink: GlkOte needs to be able to allow typing at the same time as window resizing. As I mentioned in the previous post, bump the timer delay from 0.2 up to 3.0 and you can see that GlkOte comes along and causes the keyboard to disappear/reappear in the redraw. Is GlkOte removing the input field from the DOM while a redraw is happening?

I put together an app called FictionRunner that can host Quixe+GlkOte right off your Android device - it has a built in web server on port 8081 you can access from local browsers or local LAN. It can also search your /sdcard/ path for Glulx story data files and serve those to the browser. I used this to help look at the GlkOte code offline and with my own story files easily. APK here for download on GitHub: github.com/WakeRealityDev/Scree … ase_r8.apk (r8)

It also has a built in WebView to you can see how it compares to Chrome browser in behavior -including full screen Immersive mode to play with.

The app crashes immediately for me. There are easier ways to load a story file than running a local web server, though. For example, you can use an HTML5 file reader to load a story file as a base 64 encoded binary string and pass it to gi_load()

I’ll look into why it might crash. “use an HTML5 file reader” - as in Chrome or Firefox?

Yes, like so :

developer.mozilla.org/en-US/doc … dAsDataURL

It works on Chrome on Android, as well as Cordova-compiled websites. Tried it out myself.

You do have to slice the first 13 characters of metadata that result from the method

Here is an update, r8: github.com/WakeRealityDev/Scree … ase_r8.apk - I can’t see any obvious cause for an immediate crash. If you have time to waste, try the new one and if it crashes - what is logcat showing? What Android version are you on? Thanks.

Logcat is not showing me any errors; granted, I’m running it on-device without root access using catlog.

I’m running Android 7.0 on an S8.

Here’s a Cordova build of Quixe with those two lines commented out that loads local files without a web server.

dropbox.com/s/bchq5i0v5pwyx … g.apk?dl=0

cool.

Ok, after 2 hours of failing to figure out why on a remote S8 from Samsung’s website - I think I figured out the APK I’m uploading to github is bad every time :wink: Time for a break from this. UPDATE: Confirmed, all the APK’s were corrupt, they install, but don’t run.

Back to GlkOte - I noticed quick testing various Glulx stories that even classic two-window stories (TextBuffer story narative, top Score/Status window) seem to hide/show keyboard when you do routine moves like “Go west” to another room. Is that what GlkOte assumes, that every time a player puts input into the Glulx system that the html input field should go away from the DOM? I need to find a decent test case to show this - as most stories run pretty fast and you I only really saw it when a story was slow between story frames.

If you have spare time, give R8 a try of the APK: github.com/WakeRealityDev/Scree … ase_r8.apk - this is a release build, so previous build will need to be uninstalled.

That apk works for me, however as you mentioned, the keyboard issue is not resolved in either of our apps by commenting out those lines.

Actually the Quixe in FictionRunner is pure off github, it isn’t modified. The app serves to show if the internal WebView of Android had the same issues as Chrome. I mostly wanted a tool to run the browser off my SD card files, as that’s where all my IF stories are at these days.

At this point I’m hoping someone on the “design side” of Quixe+GlkOte wants to chime in on what is the intended behavior and thinking. is it using an HTML input field that is being removed on every “go west” turn between player and Glulx engine. If that’s the case, it somewhat makes sense that Android would respond by hiding the keyboard - as it has no idea that the HTML input field is coming back nearly instantly.

I don’t feel like that behavior has been confirmed - is it removing the input field? I have not delved into the code enough yet to know.

If so, i would suggest a solution to consider: adding a second input field, hidden, and shifting focus to it before removing the functioning input control.

Shifting focus between input elements would still trigger the soft keyboard, I believe.