diff --git a/.editorconfig b/.editorconfig index 615b04483f..3b02053a52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ charset = utf-8 trim_trailing_whitespace = false insert_final_newline = false -[*.{i6t,neptune,w}] +[*.{i6t,i7,i7x,neptune,ni,txt,w}] indent_style = tab [*.json] diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7x b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7x index f800ea1612..2ea31e2a02 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7x +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7x @@ -156,26 +156,26 @@ First startup rule (this is the virtual machine startup rule): Section - Startup A (for Glulx only) -The start capturing startup text rule is listed in the before starting the virtual machine rules. -The start capturing startup text rule translates into Inter as "CAPTURE_STARTUP_TEXT_R". +The recover Glk objects rule is listed first in the before starting the virtual machine rules. [5th] +The recover Glk objects rule translates into Inter as "GGRecoverObjects". Section - Startup B -The platform specific startup rule is listed in the before starting the virtual machine rules. -The platform specific startup rule translates into Inter as "PLATFORM_SPECIFIC_STARTUP_R". +The seed random number generator rule is listed first in the before starting the virtual machine rules. [4th] +The seed random number generator rule translates into Inter as "SEED_RANDOM_NUMBER_GENERATOR_R". -The initialise memory rule is listed in the before starting the virtual machine rules. +The initialise memory rule is listed first in the before starting the virtual machine rules. [3rd] The initialise memory rule translates into Inter as "INITIALISE_MEMORY_R". -The seed random number generator rule is listed in the before starting the virtual machine rules. -The seed random number generator rule translates into Inter as "SEED_RANDOM_NUMBER_GENERATOR_R". +The platform specific startup rule is listed first in the before starting the virtual machine rules. [2nd] +The platform specific startup rule translates into Inter as "PLATFORM_SPECIFIC_STARTUP_R". Section - Startup C (for Glulx only) -The recover Glk objects rule is listed in the before starting the virtual machine rules. -The recover Glk objects rule translates into Inter as "GGRecoverObjects". +The start capturing startup text rule is listed first in the before starting the virtual machine rules. [1st] +The start capturing startup text rule translates into Inter as "CAPTURE_STARTUP_TEXT_R". -The set default stylehints rule is listed in the before starting the virtual machine rules. +The set default stylehints rule is listed in the before starting the virtual machine rules. [6th] The set default stylehints rule translates into Inter as "SET_DEFAULT_STYLEHINTS_R". The sound channel initialisation rule is listed in the for starting the virtual machine rules. @@ -1645,6 +1645,9 @@ To fill/redraw the/-- status bar/line/window with (new status table - a table-na To move the status bar/line/window cursor to row (row - number) column (col - number): (- VM_MoveCursorInStatusLine({row}, {col}); -). +To set the status bar/line/window to (rows - number) row/rows: + (- VM_StatusLineHeight({rows}); -). + Chapter 10 - External Files (not for Z-machine) Section 1 - Files of Text @@ -1703,34 +1706,15 @@ To decide which number is the patch version of (V - version number): Chapter - Glk and Glulx feature testing -To decide whether (F - glk feature) is/are supported - (documented at ph_glksupported): - (- Cached_Glk_Gestalts-->({F}) -). +Definition: a glk feature is supported rather than unsupported if I6 routine + "GlkFeatureTest" says so (it is supported by the interpreter). To decide what version number is the glk version number/-- (documented at ph_glkversion): (- VERSION_NUMBER_TY_NewFromPacked(Cached_Glk_Gestalts-->gestalt_Version) -). -To decide whether buffer window graphics are/is supported: - (- glk_gestalt(gestalt_DrawImage, wintype_TextBuffer) -). - -To decide whether graphics window graphics are/is supported: - (- glk_gestalt(gestalt_DrawImage, wintype_Graphics) -). - -To decide whether buffer window hyperlinks are/is supported: - (- glk_gestalt(gestalt_HyperlinkInput, wintype_TextBuffer) -). - -To decide whether grid window hyperlinks are/is supported: - (- glk_gestalt(gestalt_HyperlinkInput, wintype_TextGrid) -). - -To decide whether graphics window mouse input is supported: - (- glk_gestalt(gestalt_MouseInput, wintype_Graphics) -). - -To decide whether grid window mouse input is supported: - (- glk_gestalt(gestalt_MouseInput, wintype_TextGrid) -). - -To decide whether (F - glulx feature) is/are supported: - (- Cached_Glulx_Gestalts-->({F}) -). +Definition: a glulx feature is supported rather than unsupported if I6 routine + "GlulxFeatureTest" says so (it is supported by the interpreter). To decide what version number is the glulx version number/--: (- VERSION_NUMBER_TY_NewFromPacked(Cached_Glulx_Gestalts-->GLULX_GESTALT_GlulxVersion) -). @@ -1744,26 +1728,30 @@ A glk window is a kind of abstract object. The glk window kind is accessible to Inter as "K_Glk_Window". The specification of a glk window is "Models the Glk window system." -A glk window has a glk window type called the type. -The type property translates into Inter as "glk_window_type". +A glk window has a glk window type called the window type. +The window type property translates into Inter as "glk_window_type". A glk window has a number called the rock number. The rock number property translates into Inter as "glk_rock". -A glk window has a number called the reference number. -The reference number property translates into Inter as "glk_ref". +A glk window has a number called the glk window handle. +The glk window handle property translates into Inter as "glk_ref". -The main window is a glk window. +A graphics window is a kind of glk window. +The window type of a graphics window is graphics window type. +A text buffer window is a kind of glk window. +The window type of a text buffer window is text buffer window type. +A text grid window is a kind of glk window. +The window type of a text grid window is text grid window type. + +The main window is a text buffer window. The main window object is accessible to Inter as "Main_Window". -The type of the main window is text buffer. -The status window is a glk window. +The status window is a text grid window. The status window object is accessible to Inter as "Status_Window". -The type of the status window is text grid. -The quote window is a glk window. +The quote window is a text buffer window. The quote window object is accessible to Inter as "Quote_Window". -The type of the quote window is text buffer. The unknown window is a glk window. The unknown window object is accessible to Inter as "Unknown_Glk_Window". @@ -1772,30 +1760,28 @@ Section - Glk windows To clear (win - a glk window) (documented at ph_glkwindowclear): - (- glk_window_clear({win}.glk_ref); -). + (- WindowClear({win}); -). To focus (win - a glk window) (documented at ph_glkwindowfocus): - (- glk_set_window({win}.glk_ref); -). + (- WindowFocus({win}); -). To decide what number is the height of (win - a glk window) (documented at ph_glkwindowheight): - (- GetWindowSize({win}, 1) -). + (- WindowGetSize({win}, 1) -). To decide what number is the width of (win - a glk window) (documented at ph_glkwindowwidth): - (- GetWindowSize({win}, 0) -). + (- WindowGetSize({win}, 0) -). To set (win - a glk window) cursor to row (row - a number) and/-- column (col - a number): - (- glk_window_move_cursor({win}.glk_ref, {col} - 1, {row} - 1); -). + (- WindowMoveCursor({win}, {col}, {row}); -). Chapter - Glk events The glk event handling rules is a glk event based rulebook. The glk event handling rules is accessible to Inter as "GLK_EVENT_HANDLING_RB". -The glk event type is a glk event variable. -The glk event type variable translates into Inter as "Glk_Event_Struct_type". The glk event window is a glk window variable. The glk event window variable translates into Inter as "Glk_Event_Struct_win". The glk event value 1 is a number variable. @@ -1812,18 +1798,20 @@ Definition: a glk event is dependent on the player rather than independent of th To set the/-- glk event type to (t - glk event): (- SetGlkEventType({t}); -). +To say current line input of (w - glk window): + (- WindowBufferPrint({w}); -). + To decide what text is the current line input of (w - glk window): - (- CopyWindowBufferToText({w}, {-new:text}) -). + (- WindowBufferCopyToText({w}, {-new:text}) -). To set the current line input of (w - glk window) to (t - text): - (- CopyTextToWindowBuffer({w}, {-by-reference:t}); -). + (- WindowBufferSet({w}, {-by-reference:t}); -). -First glk event handling rule (this is the update text input status rule): - if the glk event type is character event or the glk event type is line event: - now the text input status of the glk event window is inactive text input; - if the glk event type is hyperlink event: +First glk event handling rule for a glk event (called the event) (this is the update input requests rule): + [ It was too risky to set the text input status here, in case the author also sets a first glk event handling rule, so that property is reset within glk_select. ] + if the event is hyperlink event: now the glk event window is not requesting hyperlink input; - if the glk event type is mouse event: + if the event is mouse event: now the glk event window is not requesting mouse input; Chapter - Suspending and resuming input diff --git a/inform7/Internal/Inter/Architecture32Kit/RTPs/ClosedWindow.md b/inform7/Internal/Inter/Architecture32Kit/RTPs/ClosedWindow.md new file mode 100644 index 0000000000..bde436bead --- /dev/null +++ b/inform7/Internal/Inter/Architecture32Kit/RTPs/ClosedWindow.md @@ -0,0 +1,3 @@ +# Cannot perform this Glk window operation on a closed window + +A Glk window function is being called on a closed window. \ No newline at end of file diff --git a/inform7/Internal/Inter/Architecture32Kit/RTPs/NoWindow.md b/inform7/Internal/Inter/Architecture32Kit/RTPs/NoWindow.md new file mode 100644 index 0000000000..3c683f0523 --- /dev/null +++ b/inform7/Internal/Inter/Architecture32Kit/RTPs/NoWindow.md @@ -0,0 +1,3 @@ +# Cannot perform this Glk window operation on nothing + +A Glk window function is being called on nothing. This could happen, for example, if you're assuming the `glk event window` is valid, but for timer events it is nothing. \ No newline at end of file diff --git a/inform7/Internal/Inter/Architecture32Kit/RTPs/SetTextEventWithoutWindow.md b/inform7/Internal/Inter/Architecture32Kit/RTPs/SetTextEventWithoutWindow.md new file mode 100644 index 0000000000..c88d2a425f --- /dev/null +++ b/inform7/Internal/Inter/Architecture32Kit/RTPs/SetTextEventWithoutWindow.md @@ -0,0 +1,3 @@ +# Can't set the glk event type to a text input event when there is no glk event window + +The glk event type cannot be changed to a text input event (character or line) if the `glk event window` is currently unset (such as in a timer event). \ No newline at end of file diff --git a/inform7/Internal/Inter/Architecture32Kit/RTPs/WindowHasNoBuffer.md b/inform7/Internal/Inter/Architecture32Kit/RTPs/WindowHasNoBuffer.md new file mode 100644 index 0000000000..5a23eb2d8d --- /dev/null +++ b/inform7/Internal/Inter/Architecture32Kit/RTPs/WindowHasNoBuffer.md @@ -0,0 +1,3 @@ +# Cannot set current line input of a window which has never requested line input + +In order to use the `set the current line input` phrase, the window must previously have requested line input. For example, you cannot set the current line input of a graphics window. \ No newline at end of file diff --git a/inform7/Internal/Inter/Architecture32Kit/RTPs/WrongWindowType.md b/inform7/Internal/Inter/Architecture32Kit/RTPs/WrongWindowType.md new file mode 100644 index 0000000000..8e1bfbb8ca --- /dev/null +++ b/inform7/Internal/Inter/Architecture32Kit/RTPs/WrongWindowType.md @@ -0,0 +1,3 @@ +# Wrong window type for this Glk window operation + +A Glk window function is being called on a window with the wrong window type, for example, setting the cursor on a buffer window, or using graphics window functions on a grid window. \ No newline at end of file diff --git a/inform7/Internal/Inter/Architecture32Kit/Sections/Glk.i6t b/inform7/Internal/Inter/Architecture32Kit/Sections/Glk.i6t index 2ecd142400..e15eb23922 100644 --- a/inform7/Internal/Inter/Architecture32Kit/Sections/Glk.i6t +++ b/inform7/Internal/Inter/Architecture32Kit/Sections/Glk.i6t @@ -10,15 +10,27 @@ General Glk constants and properties. = Constant GLK_NULL 0; -! Can't use gestalt_GarglkText_FAKE or GLULX_GESTALT_Double here as they don't have the correct values yet -Array Cached_Glk_Gestalts --> (24 + 1); -Array Cached_Glulx_Gestalts --> (13 + 1); - Property line_input_buffer_addr; Property line_input_buffer_curlen; Property line_input_buffer_maxlen; Property line_input_buffer_uni; +@h Glk/Glulx gestalts. +A few small definitions for handling Glk/Glulx gestalts. + += +! Can't use gestalt_GarglkText_FAKE or GLULX_GESTALT_Double here as they don't have the correct values yet +Array Cached_Glk_Gestalts --> (24 + 7); +Array Cached_Glulx_Gestalts --> (13 + 1); + +[ GlkFeatureTest id; + return Cached_Glk_Gestalts-->id; +]; + +[ GlulxFeatureTest id; + return Cached_Glulx_Gestalts-->id; +]; + @h Glk object recovery. |GGRecoverObjects| handles recovering the Glk objects after restarting or restoring. @@ -63,8 +75,11 @@ Global current_glk_object_reference = 0; = [ RESET_GLK_REFERENCES_R; + Main_Window.glk_ref = 0; Main_Window.glk_rock = GG_MAINWIN_ROCK; + Status_Window.glk_ref = 0; Status_Window.glk_rock = GG_STATUSWIN_ROCK; + Quote_Window.glk_ref = 0; Quote_Window.glk_rock = GG_QUOTEWIN_ROCK; gg_mainwin = 0; gg_statuswin = 0; @@ -85,6 +100,12 @@ Global current_glk_object_reference = 0; Cached_Glk_Gestalts-->ix = glk_gestalt(ix, 0); } Cached_Glk_Gestalts-->gestalt_GarglkText_FAKE = glk_gestalt(gestalt_GarglkText, 0); + Cached_Glk_Gestalts-->gestalt_DrawImage_BUFFER = glk_gestalt(gestalt_DrawImage, wintype_TextBuffer); + Cached_Glk_Gestalts-->gestalt_DrawImage_GRAPHICS = glk_gestalt(gestalt_DrawImage, wintype_Graphics); + Cached_Glk_Gestalts-->gestalt_HyperlinkInput_BUFFER = glk_gestalt(gestalt_HyperlinkInput, wintype_TextBuffer); + Cached_Glk_Gestalts-->gestalt_HyperlinkInput_GRID = glk_gestalt(gestalt_HyperlinkInput, wintype_TextGrid); + Cached_Glk_Gestalts-->gestalt_MouseInput_GRAPHICS = glk_gestalt(gestalt_MouseInput, wintype_Graphics); + Cached_Glk_Gestalts-->gestalt_MouseInput_GRID = glk_gestalt(gestalt_MouseInput, wintype_TextGrid); for (ix = 0: ix <= GLULX_GESTALT_Double: ix++) { @gestalt ix 0 res; Cached_Glulx_Gestalts-->ix = res; @@ -157,8 +178,49 @@ Global current_glk_object_reference = 0; Functions for minimal Glk windows support. = -[ CopyTextToWindowBuffer win txt +[ FindGlkWindowFromRefNum ref win; + if (ref ~= 0) { + for (win = K_Glk_Window_First: win: win = win.K_Glk_Window_Next) { + if (win.glk_ref == ref) { + return win; + } + } + } + return nothing; +]; + +[ WindowBufferCopyToText win txt buf_type; + if (win && win.line_input_buffer_addr) { + if (win.line_input_buffer_uni) { + buf_type = 4; + ! I don't remember why I was setting 0 here + !win.line_input_buffer_addr-->(win.line_input_buffer_curlen) = 0; + } + else { + buf_type = 1; + !win.line_input_buffer_addr->(win.line_input_buffer_curlen) = 0; + } + BlkValueMassCopyFromArray(txt, win.line_input_buffer_addr, buf_type, win.line_input_buffer_curlen); + } + return txt; +]; + +[ WindowBufferPrint win; + if (win && win.line_input_buffer_addr) { + glk_put_buffer_uni(win.line_input_buffer_addr, win.line_input_buffer_curlen); + } +]; + +[ WindowBufferSet win txt buf ch cp i len p uni; + if (~~win) { + IssueRTP("NoWindow", "WindowCopyTextToBuffer: Cannot perform this Glk window operation on nothing.", Architecture32KitRTPs); + return; + } + if (win.line_input_buffer_addr == 0) { + IssueRTP("WindowHasNoBuffer", "Cannot set current line input of a window which has never requested line input.", Architecture32KitRTPs); + return; + } buf = win.line_input_buffer_addr; uni = win.line_input_buffer_uni; cp = txt-->0; @@ -184,40 +246,57 @@ Functions for minimal Glk windows support. win.line_input_buffer_curlen = i; ]; -[ CopyWindowBufferToText win txt buf_type; - if (win.line_input_buffer_uni) { - buf_type = 4; - ! I don't remember why I was setting 0 here - !win.line_input_buffer_addr-->(win.line_input_buffer_curlen) = 0; - } - else { - buf_type = 1; - !win.line_input_buffer_addr->(win.line_input_buffer_curlen) = 0; +[ WindowClear win; + if (win && win.glk_ref) { + glk_window_clear(win.glk_ref); } - BlkValueMassCopyFromArray(txt, win.line_input_buffer_addr, buf_type, win.line_input_buffer_curlen); - return txt; ]; -[ FindGlkWindowFromRefNum ref win; - if (ref ~= 0) { - for (win = K_Glk_Window_First: win: win = win.K_Glk_Window_Next) { - if (win.glk_ref == ref) { - return win; - } +[ WindowFillInDetails win ref; + win.glk_ref = ref; + win.glk_rock = glk_window_get_rock(ref); + win.glk_window_type = glk_window_get_type(ref); +]; + +[ WindowFocus win; + if (win) { + if (win.glk_ref) { + glk_set_window(win.glk_ref); + } + else { + IssueRTP("ClosedWindow", "WindowFocus: Cannot perform this Glk window operation on a closed window.", Architecture32KitRTPs); } } - return nothing; + else { + IssueRTP("NoWindow", "WindowFocus: Cannot perform this Glk window operation on nothing.", Architecture32KitRTPs); + } ]; -[ FillInWindowDetails win ref; - win.glk_ref = ref; - win.glk_rock = glk_window_get_rock(ref); - win.glk_window_type = glk_window_get_type(ref); +[ WindowGetSize win index; + if (win && win.glk_ref) { + glk_window_get_size(win.glk_ref, gg_arguments, gg_arguments + WORDSIZE); + return gg_arguments-->index; + } + return 0; ]; -[ GetWindowSize win index; - glk_window_get_size(win.glk_ref, gg_arguments, gg_arguments + WORDSIZE); - return gg_arguments-->index; +[ WindowMoveCursor win col row; + if (win) { + if (win.glk_ref) { + if (win.glk_window_type == wintype_TextGrid) { + glk_window_move_cursor(win.glk_ref, col - 1, row - 1); + } + else { + IssueRTP("WrongWindowType", "WindowMoveCursor: Wrong window type for this Glk window operation.", Architecture32KitRTPs); + } + } + else { + IssueRTP("ClosedWindow", "WindowMoveCursor: Cannot perform this Glk window operation on a closed window.", Architecture32KitRTPs); + } + } + else { + IssueRTP("NoWindow", "WindowMoveCursor: Cannot perform this Glk window operation on nothing.", Architecture32KitRTPs); + } ]; @h Glk events. @@ -229,6 +308,7 @@ Global Glk_Event_Struct_type; Global Glk_Event_Struct_win; Global Glk_Event_Struct_val1; Global Glk_Event_Struct_val2; +Global glk_event_type_changed; [ glk_select event_struct; ! Call the real glk_select @@ -250,19 +330,27 @@ Global Glk_Event_Struct_val2; ! If no window was found, then use the unknown window if (Glk_Event_Struct_win == nothing) { Glk_Event_Struct_win = Unknown_Glk_Window; - FillInWindowDetails(Unknown_Glk_Window, event_struct-->1); + WindowFillInDetails(Unknown_Glk_Window, event_struct-->1); } ! If the current event type is line input, copy the buffer length if (Glk_Event_Struct_type == evtype_LineInput) { Glk_Event_Struct_win.line_input_buffer_curlen = Glk_Event_Struct_val1; + ! And update the text input status here because it's too risky to leave for a glk event handling rule + Glk_Event_Struct_win.text_input_status = INPUT_STATUS_NONE; + } + else if (Glk_Event_Struct_type == evtype_CharInput) { + Glk_Event_Struct_win.text_input_status = INPUT_STATUS_NONE; } } ! Run the glk event handling rules (but disable rules debugging because it crashes if keyboard input events are pending) @push debug_rules; @push say__p; @push say__pc; debug_rules = false; ClearParagraphing(1); - FollowRulebook(GLK_EVENT_HANDLING_RB, Glk_Event_Struct_type, true); + do { + glk_event_type_changed = 0; + FollowRulebook(GLK_EVENT_HANDLING_RB, Glk_Event_Struct_type, true); + } until (glk_event_type_changed == 0); @pull say__pc; @pull say__p; @pull debug_rules; ! If the current event type is line input, update the current buffer length @@ -290,16 +378,26 @@ input requests are pending, which means the new event could be ignored. = [ SetGlkEventType type; + if (type == Glk_Event_Struct_type) { + return; + } if (type == evtype_CharInput or evtype_LineInput) { - if (Glk_Event_Struct_win.text_input_status == INPUT_STATUS_ACTIVE_CHAR or INPUT_STATUS_ACTIVE_CHAR_UNI) { - glk_cancel_char_event(Glk_Event_Struct_win.glk_ref); + if (Glk_Event_Struct_win) { + if (Glk_Event_Struct_win.text_input_status == INPUT_STATUS_ACTIVE_CHAR or INPUT_STATUS_ACTIVE_CHAR_UNI) { + glk_cancel_char_event(Glk_Event_Struct_win.glk_ref); + } + else if (Glk_Event_Struct_win.text_input_status == INPUT_STATUS_ACTIVE_LINE or INPUT_STATUS_ACTIVE_LINE_UNI) { + glk_cancel_line_event(Glk_Event_Struct_win.glk_ref); + } + Glk_Event_Struct_win.text_input_status = INPUT_STATUS_NONE; } - else if (Glk_Event_Struct_win.text_input_status == INPUT_STATUS_ACTIVE_LINE or INPUT_STATUS_ACTIVE_LINE_UNI) { - glk_cancel_line_event(Glk_Event_Struct_win.glk_ref); + else { + IssueRTP("SetTextEventWithoutWindow", "You can't set the glk event type to a text input event when there is no glk event window.", Architecture32KitRTPs); } - Glk_Event_Struct_win.text_input_status = INPUT_STATUS_NONE; } Glk_Event_Struct_type = type; + glk_event_type_changed = 1; + RulebookSucceeds(); ]; @h Tracking input requests. @@ -430,31 +528,35 @@ input requests. = [ SuspendTextInput win no_input_echoing; - if (win.text_input_status == INPUT_STATUS_ACTIVE_CHAR or INPUT_STATUS_ACTIVE_CHAR_UNI) { - glk_cancel_char_event(win.glk_ref); - } - else if (win.text_input_status == INPUT_STATUS_ACTIVE_LINE or INPUT_STATUS_ACTIVE_LINE_UNI) { - glk_cancel_line_event(win.glk_ref); - ! Manually echo the command if required - if (BasicInformKit`MANUAL_INPUT_ECHOING_CFGF && Cached_Glk_Gestalts-->gestalt_LineInputEcho && no_input_echoing == 0) { - glk_set_style(style_Input); - glk_put_buffer_uni(win.line_input_buffer_addr, win.line_input_buffer_curlen); - glk_set_style(style_Normal); - glk_put_char(10); ! newline + if (win && win.glk_ref) { + if (win.text_input_status == INPUT_STATUS_ACTIVE_CHAR or INPUT_STATUS_ACTIVE_CHAR_UNI) { + glk_cancel_char_event(win.glk_ref); + } + else if (win.text_input_status == INPUT_STATUS_ACTIVE_LINE or INPUT_STATUS_ACTIVE_LINE_UNI) { + glk_cancel_line_event(win.glk_ref); + ! Manually echo the command if required + if (BasicInformKit`MANUAL_INPUT_ECHOING_CFGF && Cached_Glk_Gestalts-->gestalt_LineInputEcho && no_input_echoing == 0) { + glk_set_style(style_Input); + glk_put_buffer_uni(win.line_input_buffer_addr, win.line_input_buffer_curlen); + glk_set_style(style_Normal); + glk_put_char(10); ! newline + } } } ]; [ ResumeTextInput win; - switch (win.text_input_status) { - INPUT_STATUS_SUSPENDED_CHAR: - glk_request_char_event(win.glk_ref); - INPUT_STATUS_SUSPENDED_CHAR_UNI: - glk_request_char_event_uni(win.glk_ref); - INPUT_STATUS_SUSPENDED_LINE: - glk_request_line_event(win.glk_ref, win.line_input_buffer_addr, win.line_input_buffer_maxlen, win.line_input_buffer_curlen); - INPUT_STATUS_SUSPENDED_LINE_UNI: - glk_request_line_event_uni(win.glk_ref, win.line_input_buffer_addr, win.line_input_buffer_maxlen, win.line_input_buffer_curlen); + if (win && win.glk_ref) { + switch (win.text_input_status) { + INPUT_STATUS_SUSPENDED_CHAR: + glk_request_char_event(win.glk_ref); + INPUT_STATUS_SUSPENDED_CHAR_UNI: + glk_request_char_event_uni(win.glk_ref); + INPUT_STATUS_SUSPENDED_LINE: + glk_request_line_event(win.glk_ref, win.line_input_buffer_addr, win.line_input_buffer_maxlen, win.line_input_buffer_curlen); + INPUT_STATUS_SUSPENDED_LINE_UNI: + glk_request_line_event_uni(win.glk_ref, win.line_input_buffer_addr, win.line_input_buffer_maxlen, win.line_input_buffer_curlen); + } } ]; diff --git a/inform7/Internal/Inter/Architecture32Kit/Sections/Input Output.i6t b/inform7/Internal/Inter/Architecture32Kit/Sections/Input Output.i6t index 6e4ac763df..5ce47990f9 100644 --- a/inform7/Internal/Inter/Architecture32Kit/Sections/Input Output.i6t +++ b/inform7/Internal/Inter/Architecture32Kit/Sections/Input Output.i6t @@ -350,6 +350,7 @@ Constant UnicodeWhitespaceLen = 8; if (gg_quotewin) { glk_window_close(gg_quotewin, 0); gg_quotewin = 0; + Quote_Window.glk_ref = 0; } ]; @@ -731,6 +732,7 @@ make little sense there. if (gg_quotewin) { glk_window_close(gg_quotewin, 0); gg_quotewin = 0; + Quote_Window.glk_ref = 0; } } if (gg_statuswin && window == WIN_ALL or WIN_STATUS) glk_window_clear(gg_statuswin); diff --git a/inform7/Internal/Inter/Architecture32Kit/kinds/Glk.neptune b/inform7/Internal/Inter/Architecture32Kit/kinds/Glk.neptune index 287c15ec60..ea1eeb4792 100644 --- a/inform7/Internal/Inter/Architecture32Kit/kinds/Glk.neptune +++ b/inform7/Internal/Inter/Architecture32Kit/kinds/Glk.neptune @@ -5,23 +5,29 @@ new base GLK_FEATURE_TY { specification-text: Glk features which may or may not be supported by the interpreter. - instance: timers = gestalt_Timer_ = 5 - instance: glk graphics = gestalt_Graphics_ = 6 - instance: basic sounds = gestalt_Sound_ = 8 - instance: sound volume = gestalt_SoundVolume_ = 9 - instance: sound notifications = gestalt_SoundNotify_ = 10 - instance: hyperlinks = gestalt_Hyperlinks_ = 11 - instance: MOD sounds = gestalt_SoundMusic_ = 13 - instance: PNG transparency = gestalt_GraphicsTransparency_ = 14 - instance: glk unicode = gestalt_Unicode_ = 15 - instance: unicode normalization = gestalt_UnicodeNorm_ = 16 - instance: line input echo suppression = gestalt_LineInputEcho_ = 17 - instance: line input terminators = gestalt_LineTerminators_ = 18 - instance: system clock = gestalt_DateTime_ = 20 - instance: extended sounds = gestalt_Sound2_ = 21 - instance: resource streams = gestalt_ResourceStream_ = 22 - instance: graphics window character input = gestalt_GraphicsCharInput_ = 23 - instance: text formatting = gestalt_GarglkText_FAKE = 24 + instance: timers feature = gestalt_Timer_ = 5 + instance: glk graphics feature = gestalt_Graphics_ = 6 + instance: basic sounds feature = gestalt_Sound_ = 8 + instance: sound volume feature = gestalt_SoundVolume_ = 9 + instance: sound notifications feature = gestalt_SoundNotify_ = 10 + instance: hyperlinks feature = gestalt_Hyperlinks_ = 11 + instance: MOD sounds feature = gestalt_SoundMusic_ = 13 + instance: PNG transparency feature = gestalt_GraphicsTransparency_ = 14 + instance: glk unicode feature = gestalt_Unicode_ = 15 + instance: unicode normalization feature = gestalt_UnicodeNorm_ = 16 + instance: line input echo suppression feature = gestalt_LineInputEcho_ = 17 + instance: line input terminators feature = gestalt_LineTerminators_ = 18 + instance: system clock feature = gestalt_DateTime_ = 20 + instance: extended sounds feature = gestalt_Sound2_ = 21 + instance: resource streams feature = gestalt_ResourceStream_ = 22 + instance: graphics window character input feature = gestalt_GraphicsCharInput_ = 23 + instance: text formatting feature = gestalt_GarglkText_FAKE = 24 + instance: buffer window graphics feature = gestalt_DrawImage_BUFFER = 25 + instance: graphics window graphics feature = gestalt_DrawImage_GRAPHICS = 26 + instance: buffer window hyperlinks feature = gestalt_HyperlinkInput_BUFFER = 27 + instance: grid window hyperlinks feature = gestalt_HyperlinkInput_GRID = 28 + instance: graphics window mouse input feature = gestalt_MouseInput_GRAPHICS = 29 + instance: grid window mouse input feature = gestalt_MouseInput_GRID = 30 } new base GLULX_FEATURE_TY { @@ -31,15 +37,15 @@ new base GLULX_FEATURE_TY { specification-text: Glulx features which may or may not be supported by the interpreter. - instance: memory resizing = GLULX_GESTALT_ResizeMem = 2 - instance: undo = GLULX_GESTALT_Undo = 3 - instance: glulx unicode = GLULX_GESTALT_Unicode = 5 - instance: memory copying = GLULX_GESTALT_MemCopy = 6 - instance: memory allocations = GLULX_GESTALT_MAlloc = 7 - instance: glulx acceleration = GLULX_GESTALT_Acceleration = 9 - instance: real numbers = GLULX_GESTALT_Float = 11 - instance: extended undo = GLULX_GESTALT_ExtUndo = 12 - instance: double precision real numbers = GLULX_GESTALT_Double = 13 + instance: memory resizing feature = GLULX_GESTALT_ResizeMem = 2 + instance: undo feature = GLULX_GESTALT_Undo = 3 + instance: glulx unicode feature = GLULX_GESTALT_Unicode = 5 + instance: memory copying feature = GLULX_GESTALT_MemCopy = 6 + instance: memory allocations feature = GLULX_GESTALT_MAlloc = 7 + instance: glulx acceleration feature = GLULX_GESTALT_Acceleration = 9 + instance: real numbers feature = GLULX_GESTALT_Float = 11 + instance: extended undo feature = GLULX_GESTALT_ExtUndo = 12 + instance: double precision real numbers feature = GLULX_GESTALT_Double = 13 } new base GLK_EVENT_TY { @@ -49,16 +55,16 @@ new base GLK_EVENT_TY { specification-text: A Glk event sent from the interpreter. - instance: null event = evtype_None_ = 0 - instance: timer event = evtype_Timer_ = 1 - instance: character event = evtype_CharInput_ = 2 - instance: line event = evtype_LineInput_ = 3 - instance: mouse event = evtype_MouseInput_ = 4 - instance: arrange event = evtype_Arrange_ = 5 - instance: redraw event = evtype_Redraw_ = 6 - instance: sound notification event = evtype_SoundNotify_ = 7 - instance: hyperlink event = evtype_Hyperlink_ = 8 - instance: volume event = evtype_VolumeNotify_ = 9 + instance: null event = evtype_None_ = 0 + instance: timer event = evtype_Timer_ = 1 + instance: character event = evtype_CharInput_ = 2 + instance: line event = evtype_LineInput_ = 3 + instance: mouse event = evtype_MouseInput_ = 4 + instance: screen resize event = evtype_Arrange_ = 5 + instance: graphics window lost event = evtype_Redraw_ = 6 + instance: sound notification event = evtype_SoundNotify_ = 7 + instance: hyperlink event = evtype_Hyperlink_ = 8 + instance: volume event = evtype_VolumeNotify_ = 9 } new base GLK_WINDOW_TYPE_TY { @@ -68,9 +74,9 @@ new base GLK_WINDOW_TYPE_TY { specification-text: Type of a Glk window. - instance: text buffer = wintype_TextBuffer_ = 3 - instance: text grid = wintype_TextGrid_ = 4 - instance: graphics = wintype_Graphics_ = 5 + instance: text buffer window type = wintype_TextBuffer_ = 3 + instance: text grid window type = wintype_TextGrid_ = 4 + instance: graphics window type = wintype_Graphics_ = 5 } new base TEXT_INPUT_STATUS_TY { diff --git a/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t b/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t index ba3e99ba4a..a3e4683f2e 100644 --- a/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t +++ b/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t @@ -70,6 +70,10 @@ Array LatestRTPData --> par3 = LatestRTPData-->3; LatestRTPData-->0 = -2; +#Ifdef TARGET_GLULX; + SuspendTextInput(Main_Window); +#Endif; + print "^*** Run-time problem ", (string) name; #ifdef DEBUG; if (LatestRTPData-->5) { print ": ", (string) LatestRTPData-->5; } @@ -82,6 +86,10 @@ Array LatestRTPData --> if (desc ofclass String) print (string) desc, "^"; else if (desc ofclass Routine) desc(par1, par2, par3); } + +#Ifdef TARGET_GLULX; + ResumeTextInput(Main_Window); +#Endif; ]; @h The VeneerError RTP. diff --git a/inform7/extensions/basic_inform/Sections/Glulx and Glk.w b/inform7/extensions/basic_inform/Sections/Glulx and Glk.w index d7e8d2a4d0..5decb7400a 100644 --- a/inform7/extensions/basic_inform/Sections/Glulx and Glk.w +++ b/inform7/extensions/basic_inform/Sections/Glulx and Glk.w @@ -25,34 +25,15 @@ and so individual phrases are defined for them. = Chapter - Glk and Glulx feature testing -To decide whether (F - glk feature) is/are supported - (documented at ph_glksupported): - (- Cached_Glk_Gestalts-->({F}) -). +Definition: a glk feature is supported rather than unsupported if I6 routine + "GlkFeatureTest" says so (it is supported by the interpreter). To decide what version number is the glk version number/-- (documented at ph_glkversion): (- VERSION_NUMBER_TY_NewFromPacked(Cached_Glk_Gestalts-->gestalt_Version) -). -To decide whether buffer window graphics are/is supported: - (- glk_gestalt(gestalt_DrawImage, wintype_TextBuffer) -). - -To decide whether graphics window graphics are/is supported: - (- glk_gestalt(gestalt_DrawImage, wintype_Graphics) -). - -To decide whether buffer window hyperlinks are/is supported: - (- glk_gestalt(gestalt_HyperlinkInput, wintype_TextBuffer) -). - -To decide whether grid window hyperlinks are/is supported: - (- glk_gestalt(gestalt_HyperlinkInput, wintype_TextGrid) -). - -To decide whether graphics window mouse input is supported: - (- glk_gestalt(gestalt_MouseInput, wintype_Graphics) -). - -To decide whether grid window mouse input is supported: - (- glk_gestalt(gestalt_MouseInput, wintype_TextGrid) -). - -To decide whether (F - glulx feature) is/are supported: - (- Cached_Glulx_Gestalts-->({F}) -). +Definition: a glulx feature is supported rather than unsupported if I6 routine + "GlulxFeatureTest" says so (it is supported by the interpreter). To decide what version number is the glulx version number/--: (- VERSION_NUMBER_TY_NewFromPacked(Cached_Glulx_Gestalts-->GLULX_GESTALT_GlulxVersion) -). @@ -70,30 +51,37 @@ A glk window is a kind of abstract object. The glk window kind is accessible to Inter as "K_Glk_Window". The specification of a glk window is "Models the Glk window system." -A glk window has a glk window type called the type. -The type property translates into Inter as "glk_window_type". +A glk window has a glk window type called the window type. +The window type property translates into Inter as "glk_window_type". A glk window has a number called the rock number. The rock number property translates into Inter as "glk_rock". -A glk window has a number called the reference number. -The reference number property translates into Inter as "glk_ref". +A glk window has a number called the glk window handle. +The glk window handle property translates into Inter as "glk_ref". + +@ Setting window types is quite verbose, so we have some subkinds to make it easier. + += +A graphics window is a kind of glk window. +The window type of a graphics window is graphics window type. +A text buffer window is a kind of glk window. +The window type of a text buffer window is text buffer window type. +A text grid window is a kind of glk window. +The window type of a text grid window is text grid window type. @ Create objects for each of the built in windows, as well as the "unknown window", which is used when there's a Glk event on a window that can't be identified. = -The main window is a glk window. +The main window is a text buffer window. The main window object is accessible to Inter as "Main_Window". -The type of the main window is text buffer. -The status window is a glk window. +The status window is a text grid window. The status window object is accessible to Inter as "Status_Window". -The type of the status window is text grid. -The quote window is a glk window. +The quote window is a text buffer window. The quote window object is accessible to Inter as "Quote_Window". -The type of the quote window is text buffer. The unknown window is a glk window. The unknown window object is accessible to Inter as "Unknown_Glk_Window". @@ -107,22 +95,22 @@ Section - Glk windows To clear (win - a glk window) (documented at ph_glkwindowclear): - (- glk_window_clear({win}.glk_ref); -). + (- WindowClear({win}); -). To focus (win - a glk window) (documented at ph_glkwindowfocus): - (- glk_set_window({win}.glk_ref); -). + (- WindowFocus({win}); -). To decide what number is the height of (win - a glk window) (documented at ph_glkwindowheight): - (- GetWindowSize({win}, 1) -). + (- WindowGetSize({win}, 1) -). To decide what number is the width of (win - a glk window) (documented at ph_glkwindowwidth): - (- GetWindowSize({win}, 0) -). + (- WindowGetSize({win}, 0) -). To set (win - a glk window) cursor to row (row - a number) and/-- column (col - a number): - (- glk_window_move_cursor({win}.glk_ref, {col} - 1, {row} - 1); -). + (- WindowMoveCursor({win}, {col}, {row}); -). @h Glk events. Glk events can be handled with the glk event handling rules. @@ -133,8 +121,6 @@ Chapter - Glk events The glk event handling rules is a glk event based rulebook. The glk event handling rules is accessible to Inter as "GLK_EVENT_HANDLING_RB". -The glk event type is a glk event variable. -The glk event type variable translates into Inter as "Glk_Event_Struct_type". The glk event window is a glk window variable. The glk event window variable translates into Inter as "Glk_Event_Struct_win". The glk event value 1 is a number variable. @@ -151,18 +137,20 @@ Definition: a glk event is dependent on the player rather than independent of th To set the/-- glk event type to (t - glk event): (- SetGlkEventType({t}); -). +To say current line input of (w - glk window): + (- WindowBufferPrint({w}); -). + To decide what text is the current line input of (w - glk window): - (- CopyWindowBufferToText({w}, {-new:text}) -). + (- WindowBufferCopyToText({w}, {-new:text}) -). To set the current line input of (w - glk window) to (t - text): - (- CopyTextToWindowBuffer({w}, {-by-reference:t}); -). + (- WindowBufferSet({w}, {-by-reference:t}); -). -First glk event handling rule (this is the update text input status rule): - if the glk event type is character event or the glk event type is line event: - now the text input status of the glk event window is inactive text input; - if the glk event type is hyperlink event: +First glk event handling rule for a glk event (called the event) (this is the update input requests rule): + [ It was too risky to set the text input status here, in case the author also sets a first glk event handling rule, so that property is reset within glk_select. ] + if the event is hyperlink event: now the glk event window is not requesting hyperlink input; - if the glk event type is mouse event: + if the event is mouse event: now the glk event window is not requesting mouse input; @h Suspending input. diff --git a/inform7/extensions/basic_inform/Sections/Miscellaneous Definitions.w b/inform7/extensions/basic_inform/Sections/Miscellaneous Definitions.w index 1174bf1d4c..b10cfa947a 100644 --- a/inform7/extensions/basic_inform/Sections/Miscellaneous Definitions.w +++ b/inform7/extensions/basic_inform/Sections/Miscellaneous Definitions.w @@ -82,6 +82,8 @@ activity perform essential work before a Basic Inform project can begin. Be wary modifying these: rulebooks and activities must be defined in exactly the right order, matching definitions both in the Inform 7 compiler and in the template libraries. (Remember that creating an activity creates three rulebooks.) +(And to define rules listed "first" in the right order, we have to reverse their +order in the source code. Messy.) These rules here are the ones which get the basic machinery working to the point where it is safe to run arbitrary I7 source text. They necessarily @@ -133,29 +135,29 @@ First startup rule (this is the virtual machine startup rule): Section - Startup A (for Glulx only) -The start capturing startup text rule is listed in the before starting the virtual machine rules. -The start capturing startup text rule translates into Inter as "CAPTURE_STARTUP_TEXT_R". +The recover Glk objects rule is listed first in the before starting the virtual machine rules. [5th] +The recover Glk objects rule translates into Inter as "GGRecoverObjects". Section - Startup B -The platform specific startup rule is listed in the before starting the virtual machine rules. -The platform specific startup rule translates into Inter as "PLATFORM_SPECIFIC_STARTUP_R". +The seed random number generator rule is listed first in the before starting the virtual machine rules. [4th] +The seed random number generator rule translates into Inter as "SEED_RANDOM_NUMBER_GENERATOR_R". -The initialise memory rule is listed in the before starting the virtual machine rules. +The initialise memory rule is listed first in the before starting the virtual machine rules. [3rd] The initialise memory rule translates into Inter as "INITIALISE_MEMORY_R". -The seed random number generator rule is listed in the before starting the virtual machine rules. -The seed random number generator rule translates into Inter as "SEED_RANDOM_NUMBER_GENERATOR_R". +The platform specific startup rule is listed first in the before starting the virtual machine rules. [2nd] +The platform specific startup rule translates into Inter as "PLATFORM_SPECIFIC_STARTUP_R". Section - Startup C (for Glulx only) -The recover Glk objects rule is listed in the before starting the virtual machine rules. -The recover Glk objects rule translates into Inter as "GGRecoverObjects". +The start capturing startup text rule is listed first in the before starting the virtual machine rules. [1st] +The start capturing startup text rule translates into Inter as "CAPTURE_STARTUP_TEXT_R". @ These rules now set up the built in sound channels and windows. = -The set default stylehints rule is listed in the before starting the virtual machine rules. +The set default stylehints rule is listed in the before starting the virtual machine rules. [6th] The set default stylehints rule translates into Inter as "SET_DEFAULT_STYLEHINTS_R". The sound channel initialisation rule is listed in the for starting the virtual machine rules. diff --git a/inform7/extensions/basic_inform/Sections/Phrase Definitions.w b/inform7/extensions/basic_inform/Sections/Phrase Definitions.w index 6b6590def5..998dfa3ebf 100644 --- a/inform7/extensions/basic_inform/Sections/Phrase Definitions.w +++ b/inform7/extensions/basic_inform/Sections/Phrase Definitions.w @@ -1979,6 +1979,9 @@ To fill/redraw the/-- status bar/line/window with (new status table - a table-na To move the status bar/line/window cursor to row (row - number) column (col - number): (- VM_MoveCursorInStatusLine({row}, {col}); -). +To set the status bar/line/window to (rows - number) row/rows: + (- VM_StatusLineHeight({rows}); -). + @h External Files. Inform has a quirky level of support for file-handling, which comes out of what the Glulx virtual machine will support. diff --git a/resources/Documentation/Writing with Inform.md b/resources/Documentation/Writing with Inform.md index da0a84100b..c307cf7c9c 100644 --- a/resources/Documentation/Writing with Inform.md +++ b/resources/Documentation/Writing with Inform.md @@ -18178,23 +18178,23 @@ Here `glk feature` is a kind of value. So, for example, might produce: - timers: true. - glk graphics: true. - basic sounds: true. - sound volume: true. - sound notifications: true. - hyperlinks: true. - MOD sounds: true. - PNG transparency: true. - glk unicode: true. - unicode normalization: true. - line input echo suppression: true. - line input terminators: false. - system clock: true. - extended sounds: true. - resource streams: false. - graphics window character input: true. - text formatting: false. + timers feature: true. + glk graphics feature: true. + basic sounds feature: true. + sound volume feature: true. + sound notifications feature: true. + hyperlinks feature: true. + MOD sounds feature: true. + PNG transparency feature: true. + glk unicode feature: true. + unicode normalization feature: true. + line input echo suppression feature: true. + line input terminators feature: false. + system clock feature: true. + extended sounds feature: true. + resource streams feature: false. + graphics window character input feature: true. + text formatting feature: false. ## Dividing the screen into windows @@ -18212,18 +18212,18 @@ produces {main window, status window, quote window, unknown window} -Every glk window has a property called its `type`, which is a `glk window type` value. If we run: +Every glk window has a property called its `window type`, which is a `glk window type` value. If we run: repeat with W running through glk windows: - say "[W]: [type of W]."; + say "[W]: [window type of W]."; then we get, assuming we haven't created any extra windows or types, ``` transcript -main window: text buffer. -status window: text grid. -quote window: text buffer. -unknown window: text buffer. +main window: text buffer window type. +status window: text grid window type. +quote window: text buffer window type. +unknown window: text buffer window type. ``` So, what goes on here? @@ -18258,24 +18258,24 @@ But two phrases are included even in an unextended Inform: > > When the player types something, where do the keypresses go? The answer is that they are sent to whichever window currently has the _focus_. That's normally the `main window`, of course, but this phrase allows a switch. -Glk windows have two `number` properties, `rock number` and `reference number`: see the Glk reference documentation for what they mean. `reference number` is what the Glk spec calls the window ID, and it therefore exists only for open windows. +Glk windows have two `number` properties, `rock number` and `glk reference handle`: see the Glk reference documentation for what they mean. `glk reference handle` is what the Glk spec calls the window ID, and it therefore exists only for open windows. ## Glk events An Inform story is always in control of what it outputs. It decides what to say, and when to say it. Input is not as predictable. Somewhere outside of the story is a player, pressing keys or clicking on links. These are examples of _Glk events_, and the Inform kind `glk event` identifies them. Here is the complete list: -Value | Meaning --------------------------- | --------------------- -`null event` | Nothing happening. -`character event` | A key has been typed. -`line event` | A line of text ending with a RETURN or ENTER has been typed. -`hyperlink event` | A web-style link has been selected. -`mouse event` | A mouse has been clicked, or a touch-screen touched. -`arrange event` | The screen has been resized. -`redraw event` | A graphic window needs redrawing from scratch. -`timer event` | A timer has run out. -`sound notification event` | A sound effect has finished playing. -`volume event` | A change in sound volume has completed. +Value | Meaning +---------------------------- | --------------------- +`null event` | Nothing happening. +`character event` | A key has been typed. +`line event` | A line of text ending with a RETURN or ENTER has been typed. +`hyperlink event` | A web-style link has been selected. +`mouse event` | A mouse has been clicked, or a touch-screen touched. +`screen resize event` | The screen has been resized. +`graphics window lost event` | A graphic window needs redrawing from scratch. +`timer event` | A timer has run out. +`sound notification event` | A sound effect has finished playing. +`volume event` | A change in sound volume has completed. Note that some of these are our own fault, so to speak. If we set a timer to run for, say, ten seconds, it will in due course lead to a `timer event`. Inform defines an event as `independent of the player` if it occurred because of some earlier decision by the story, and `dependent on the player` if it occurred because of spontaneous input such as pressing a key or clicking a mouse. @@ -20450,7 +20450,7 @@ Extensions can trigger RTPs of their own, too. For example, suppose `Ducking` de issue the run-time problem "OverDucked"; say "*** ", (the) ducker, " seems to be putting their head below their feet."; -The RTP name, here `OverDucked`, must correspind exactly to the name of a Markdown file stored in an ```RTPs``` subdirectory of the extension: +The RTP name, here `OverDucked`, must correspond exactly to the name of a Markdown file stored in an ```RTPs``` subdirectory of the extension: ``` code Philately-v1.i7xd