1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Injection of input events that are read frm a file.
16 # This cloud be used to replay an execution of a mnit application to debug or to benchmark it.
18 # The input file is given through the environment variable `MNIT_READ_INPUT`
20 # In order to reproduce executions, the behavior of the application must be deterministic
21 # for a given sequence of inputs.
22 # The main source of differences in executions is caused by the `rand` function,
23 # Set the environment variable `MNIT_SRAND` to a value to force srand to be initialized with this value.
25 # The input event file is made of event descriptions, one event by line.
32 # The first field, an integer, is the delay (in frame count) since the previous event
33 # 0 means the event is launched in the same frame that the previous one.
35 # The second field, a string, is the kind of the event.
36 # Currently only `click` for PointerEvent and `quit` for QuitEvent are recognized.
38 # The following fields are the arguments that specific for each kind of event.
40 # * `quit` does not have arguments
41 # * `click` has 2 float arguments: `PointerEvent::x` and `PointerEvent::y`
42 module mnit_injected_input
46 # Concrete event objects that are manually instantiated.
47 # Most InputEvent are extern classes and specific to one platform.
49 # However, subclasses of this `DummyInputEvent` are genuine Nit
50 # classes and can be instantiated, and more easily manipulated by the programmer.
51 interface DummyInputEvent
55 # A concrete QuitEvent
59 redef fun to_s
do return "quit"
62 # A concrete PointerEvent
63 class DummyPointerEvent
68 redef fun pressed
do return true
69 redef fun to_s
do return "click {x} {y}"
73 # The stream where injected inputs are read
74 private var injected_input_stream
: nullable Reader = null
78 var env
= "MNIT_SRAND".environ
85 var input
= "MNIT_READ_INPUT".environ
87 injected_input_stream
= new FileReader.open
(input
)
88 print
"GET injected_input_stream {input}"
94 # Number of frames before the next injected input
95 private var wait_next_input
= 0
97 # What is the input to inject when `wait_next_input` become 0
98 private var next_input
: nullable DummyInputEvent
102 if injected_input_stream
!= null then generate_injected_input
106 # Internal method to generate injected input events
107 # Is called before each frame
108 # Return `true` is an input event was injexted
109 fun generate_injected_input
: Bool
113 if wait_next_input
> 0 then
123 var l
= injected_input_stream
.read_line
125 print
"END OF INPUTS"
126 injected_input_stream
.close
127 injected_input_stream
= null
128 input
(new DummyQuitEvent)
132 var fs
= l
.split
(" ")
133 if fs
.length
< 2 then
134 print
"BAD EVENT SPEC {l}"
136 input
(new DummyQuitEvent)
138 wait_next_input
= fs
[0].to_i
139 if fs
[1] == "click" then
140 next_input
= new DummyPointerEvent(fs
[2].to_f
, fs
[3].to_f
)
141 else if fs
[1] == "quit" then
142 next_input
= new DummyQuitEvent
144 print
"UNKNOWN EVENT {fs[1]} (on {l})"
146 input
(new DummyQuitEvent)
149 print
"WAIT {wait_next_input} for {next_input.to_s}"