diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-06-15 13:58:08 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-06-15 13:58:08 -0700 |
commit | a5840f21020f6d568f82f84afe9fe99047a49f4a (patch) | |
tree | 72f8b28e8166268ee38174c2c7160804956297ad | |
parent | 7c0d16a79fba21e67d3b46f12f29042f84f997ba (diff) | |
download | mu-a5840f21020f6d568f82f84afe9fe99047a49f4a.tar.gz |
1566 - fake mouse clicks in scenarios
-rw-r--r-- | 011load.cc | 3 | ||||
-rw-r--r-- | 041name.cc | 1 | ||||
-rw-r--r-- | 050scenario.cc | 2 | ||||
-rw-r--r-- | 078mouse.mu | 43 | ||||
-rw-r--r-- | 079scenario_events.cc | 149 |
5 files changed, 197 insertions, 1 deletions
diff --git a/011load.cc b/011load.cc index 7d9c3047..158e4b10 100644 --- a/011load.cc +++ b/011load.cc @@ -17,6 +17,7 @@ vector<recipe_number> load(string form) { } vector<recipe_number> load(istream& in) { + in >> std::noskipws; vector<recipe_number> result; while (!in.eof()) { //? cerr << "===\n"; //? 1 @@ -69,6 +70,7 @@ recipe slurp_recipe(istream& in) { } bool next_instruction(istream& in, instruction* curr) { + in >> std::noskipws; curr->clear(); if (in.eof()) return false; //? show_rest_of_stream(in); //? 1 @@ -82,6 +84,7 @@ bool next_instruction(istream& in, instruction* curr) { skip_whitespace(in); if (in.eof()) return false; //? show_rest_of_stream(in); //? 1 string word = next_word(in); if (in.eof()) return false; +//? cerr << "AAA: " << word << '\n'; //? 1 words.push_back(word); skip_whitespace(in); if (in.eof()) return false; } diff --git a/041name.cc b/041name.cc index dbbf8733..c3bd49fa 100644 --- a/041name.cc +++ b/041name.cc @@ -76,6 +76,7 @@ void check_metadata(map<string, vector<type_number> >& metadata, const reagent& } bool disqualified(/*mutable*/ reagent& x) { +//? cerr << x.to_string() << '\n'; //? 1 if (x.types.empty()) raise << "missing type in " << x.to_string() << '\n'; assert(!x.types.empty()); diff --git a/050scenario.cc b/050scenario.cc index ae35b8dd..1eacf58f 100644 --- a/050scenario.cc +++ b/050scenario.cc @@ -134,7 +134,7 @@ void run_mu_scenario(const scenario& s) { Trace_stream = new trace_stream; setup(); } -//? cerr << '^' << s.to_run << "$\n"; //? 2 +//? cerr << '^' << s.to_run << "$\n"; //? 3 run("recipe "+s.name+" [ " + s.to_run + " ]"); if (not_already_inside_test && Trace_stream) { teardown(); diff --git a/078mouse.mu b/078mouse.mu new file mode 100644 index 00000000..2590131f --- /dev/null +++ b/078mouse.mu @@ -0,0 +1,43 @@ +exclusive-container event [ + # update the ASSUME_EVENTS handler if you add more variants + keyboard:keyboard-event + mouse:mouse-event +] + +container keyboard-event [ + key:character +] + +container mouse-event [ + type:character + row:number + column:number +] + +container events [ + index:number + data:address:array:event +] + +recipe read-event [ + default-space:address:array:location <- new location:type, 30:literal + x:address:events <- next-ingredient + { + break-unless x:address:events + idx:address:number <- get-address x:address:events/deref, index:offset + buf:address:array:event <- get x:address:events/deref, data:offset + { + max:number <- length buf:address:array:event/deref + done?:boolean <- greater-or-equal idx:address:number/deref, max:number + break-unless done?:boolean + dummy:address:event <- new event:type + reply dummy:address:event/deref, x:address:events/same-as-ingredient:0 + } + result:event <- index buf:address:array:event/deref, idx:address:number/deref + idx:address:number/deref <- add idx:address:number/deref, 1:literal + reply result:event, x:address:events/same-as-ingredient:0 + } + # real event source + result:event <- read-keyboard-or-mouse-event + reply result:event +] diff --git a/079scenario_events.cc b/079scenario_events.cc new file mode 100644 index 00000000..72a3b8cf --- /dev/null +++ b/079scenario_events.cc @@ -0,0 +1,149 @@ +//: For testing both keyboard and mouse, use 'assume-events' rather than +//: 'assume-keyboard'. +//: +//: This layer is tightly coupled with the definition of the 'event' type. + +:(scenarios run_mu_scenario) +:(scenario events_in_scenario) +scenario events-in-scenario [ + assume-events [ + type [abc] + left-click 0, 1 + type [d] + ] + run [ + # 3 keyboard events; each event occupies 4 locations +#? $start-tracing + 1:event <- read-event events:address + 5:event <- read-event events:address + 9:event <- read-event events:address + # mouse click + 13:event <- read-event events:address + # final keyboard event + 17:event <- read-event events:address + ] + memory-should-contain [ + 1 <- 0 # type 'keyboard' + 2 <- 97 # 'a' + 3 <- 0 # unused + 4 <- 0 # unused + 5 <- 0 # type 'keyboard' + 6 <- 98 # 'b' + 7 <- 0 # unused + 8 <- 0 # unused + 9 <- 0 # type 'keyboard' + 10 <- 99 # 'c' + 11 <- 0 # unused + 12 <- 0 # unused + 13 <- 1 # type 'mouse' + 14 <- 65513 # mouse click + 15 <- 0 # row + 16 <- 1 # column + 17 <- 0 # type 'keyboard' + 18 <- 100 # 'd' + 19 <- 0 # unused + 20 <- 0 # unused + 21 <- 0 + ] +] + +// 'events' is a special variable like 'keyboard' and 'screen' +:(before "End Scenario Globals") +const long long int EVENTS = Next_predefined_global_for_scenarios++; +:(before "End Predefined Scenario Locals In Run") +Name[tmp_recipe.at(0)]["events"] = EVENTS; +:(before "End is_special_name Cases") +if (s == "events") return true; + +//: Unlike assume-keyboard, assume-events is easiest to implement as just a +//: primitive recipe. +:(before "End Primitive Recipe Declarations") +ASSUME_EVENTS, +:(before "End Primitive Recipe Numbers") +Recipe_number["assume-events"] = ASSUME_EVENTS; +:(before "End Primitive Recipe Implementations") +case ASSUME_EVENTS: { +//? cerr << "aaa: " << current_instruction().ingredients.at(0).name << '\n'; //? 1 + // create a temporary recipe just for parsing; it won't contain valid instructions + istringstream in("[" + current_instruction().ingredients.at(0).name + "]"); + recipe r = slurp_recipe(in); + long long int num_events = count_events(r); +//? cerr << "fff: " << num_events << '\n'; //? 1 + // initialize the events + long long int size = num_events*size_of_event() + /*space for length*/1; + ensure_space(size); + long long int event_data_address = Current_routine->alloc; + Memory[event_data_address] = num_events; + ++Current_routine->alloc; + for (long long int i = 0; i < SIZE(r.steps); ++i) { + const instruction& curr = r.steps.at(i); + if (curr.name == "left-click") { + Memory[Current_routine->alloc] = /*tag for 'mouse-event' variant of 'event' exclusive-container*/1; + Memory[Current_routine->alloc+1+/*offset of 'type' in 'mouse-event'*/0] = TB_KEY_MOUSE_LEFT; + Memory[Current_routine->alloc+1+/*offset of 'row' in 'mouse-event'*/1] = to_integer(curr.ingredients.at(0).name); + Memory[Current_routine->alloc+1+/*offset of 'column' in 'mouse-event'*/2] = to_integer(curr.ingredients.at(1).name); +//? cerr << "AA left click: " << Memory[Current_routine->alloc+2] << ' ' << Memory[Current_routine->alloc+3] << '\n'; //? 1 + Current_routine->alloc += size_of_event(); + } + // End Event Handlers + else { + // keyboard input + assert(curr.name == "type"); + const string& contents = curr.ingredients.at(0).name; + const char* raw_contents = contents.c_str(); + long long int num_keyboard_events = unicode_length(contents); + long long int curr = 0; + for (long long int i = 0; i < num_keyboard_events; ++i) { + Memory[Current_routine->alloc] = /*tag for 'keyboard-event' variant of 'event' exclusive-container*/0; + uint32_t curr_character; + assert(curr < SIZE(contents)); + tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]); +//? cerr << "AA keyboard: " << curr_character << '\n'; //? 1 + Memory[Current_routine->alloc+/*skip exclusive container tag*/1] = curr_character; + curr += tb_utf8_char_length(raw_contents[curr]); + Current_routine->alloc += size_of_event(); + } + } + } + assert(Current_routine->alloc == event_data_address+size); + // wrap the array of events in an event object + ensure_space(size_of_events()); + Memory[EVENTS] = Current_routine->alloc; + Current_routine->alloc += size_of_events(); + Memory[Memory[EVENTS]+/*offset of 'data' in container 'events'*/1] = event_data_address; + break; +} + +:(code) +long long int count_events(const recipe& r) { + long long int result = 0; + for (long long int i = 0; i < SIZE(r.steps); ++i) { + const instruction& curr = r.steps.at(i); +//? cerr << curr.name << '\n'; //? 1 + if (curr.name == "type") + result += unicode_length(curr.ingredients.at(0).name); + else + result++; + } + return result; +} + +long long int size_of_event() { + // memoize result if already computed + static long long int result = 0; + if (result) return result; + vector<type_number> type; + type.push_back(Type_number["event"]); + result = size_of(type); + return result; +} + +long long int size_of_events() { + // memoize result if already computed + static long long int result = 0; + if (result) return result; + vector<type_number> type; + type.push_back(Type_number["events"]); + result = size_of(type); + return result; +} |