I need to be able to wait for two types of events in the app using OCamlSDL:
User key presses
Timer events with fixed-time interval
I can see in the tutorial how to wait for events in a loop. My idea was to set up a timer using SDL_AddTimer and feed via it custom USER events which will be processed in the same loop as the keyboard events. However I do not see OCAML binding for SDL_AddTimer SDL function. How can I implement something like this?
The solution I found involves running separate POSIX thread which uses Sldevent.add to send user-defined events which are then processed in the main event processing loop with keyboard events. Here is a code except which starts the thread:
...
and timer_cb () = Sdlevent.add [USER 0] in
let timer_thread = Thread.create timer_loop (timer_flag, timer_cb) in
loop state; (* runs main program logic *)
timer_flag := true;
Thread.join timer_thread
Timer function (executed in separate thread):
let rec timer_loop (flag, callback) =
if !flag then
Thread.exit
else
(Thread.delay 0.5;
callback ();
(timer_loop (flag, callback)))
Event handling loop except:
let rec loop state =
match wait_event () with
| KEYDOWN {keysym=KEY_LEFT} ->
(* process left arrow key press here *)
loop state
| USER 0 ->
(* Process ticks here *)
loop state
| KEYDOWN {keysym=KEY_ESCAPE} ->
(* ESC to exit the app *)
()
| _ ->
loop state
Related
I have the following test:
testHarness.processElement2(new StreamRecord<>(element1));
testHarness.processElement1(new StreamRecord<>(new Tuple2<>(id, element2)));
testHarness.setProcessingTime(1); //let's assume it's the correct time for the timer inside the function
softly.assertThat(testHarness.getOutput()).containsExactly(new StreamRecord<>(expectedResult)); //this one is passed
testHarness.setProcessingTime(2); // setting second timer which will trigger different timer
softly.assertThat(testHarness.getOutput()).containsExactly(new StreamRecord<>(expectedResult2)); //fails cause output has expectedResult & expectedResult2
Why TestHarness is not clearing it's elements once we call getOutput()? Could this functionality be achieved somehow?
This can be achieved by calling clear() on the output :
testHarness.processElement2(new StreamRecord<>(element1));
testHarness.processElement1(new StreamRecord<>(new Tuple2<>(id, element2)));
testHarness.setProcessingTime(1); //let's assume it's the correct time for the timer inside the function
softly.assertThat(testHarness.getOutput()).containsExactly(new StreamRecord<>(expectedResult)); // Pass
testHarness.getOutput().clear();
testHarness.setProcessingTime(2); // setting second timer which will trigger different timer
softly.assertThat(testHarness.getOutput()).containsExactly(new StreamRecord<>(expectedResult2)); // Pass
1. Briefly
I don't understand, how I can use cycles from Loop multiple times without ending script.
2. Settings
I have a file SashaAutoScrolling.ahk, it content:
; First loop, Speed 1
#+1::
Loop
{
Send {WheelDown}
Sleep 3000
}
; Second loop, Speed 2
#+2::
Loop
{
Send {WheelDown}
Sleep 600
}
; Third loop, Speed 3
#+3::
Loop
{
Send {WheelDown}
Sleep 100
}
; Fourth loop, Speed Up
#+0::
Loop
{
Send {WheelUp}
Sleep 600
}
; Loop pause
; http://autohotkey.com/board/topic/95308-endless-loop-with-hotkey-pause/?p=600526
#p::Pause
; Exit script
#esc::ExitApp
3. Steps to reproduce
I open any pdf file in any PDF-viewer. I switch between «speeds»:
Shift+Super+3,
Shift+Super+0,
Shift+Super+2,
Shift+Super+3,
Shift+Super+0.
4. Actual behavior
If I run Shift+Super+3 and Shift+Super+0 first time
I can successful switch between «speeds».
If I run Shift+Super+3 and Shift+Super+0 second and next times,
I can't switch between «speeds».
5. Expected behavior
Successful switch between «speeds» unlimited number of times.
6. Not helped
Googling, searching in Stack Overflow and AutoHotkey forum.
7. Do not offer
Please, do not offer use third-party programs. Adobe Reader free version works as expected, but I can't read, use this program , for example, djvu or doc books.
Please, do not offer use built-in mouse auto scrolling. It uncomfortable, because is problematic quick choose exact comfortable «speed» for reading.
This code scrolls current window with simulated mouse wheel scrolls
Shift+Win+1, Shift+Win+2, etc... starts scrolling. If already scrolling, just updates sleep interval. esc exits
; globals:
; g_running : true while loop is active
; g_sleep : milliseconds to sleep between sending input event
; g_key : key to simulate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HOTKEY DEFINITIONS
#MaxThreadsPerHotkey 2
#+1:: scrollit(3000)
#+2:: scrollit(600)
#+3:: scrollit(300)
#+0:: scrollit(600,"WheelUp")
#MaxThreadsPerHotkey 1
Esc:: abort()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HELPER FUNCTIONS
; send wheeldown every _delay_ microseconds
; if called while loop is already active, just update delay and exit
;
scrollit(sleep, key="WheelDown")
{
global g_running
global g_sleep := sleep
global g_key := key
if g_running
return
g_running := true
while (g_running)
{
Send {%g_key%}
Sleep g_sleep
}
}
abort()
{
global g_running := false
}
Scrolls current window by simulating mouse wheel scroll when Shift+Win+1, Shift+Win+2, etc. pressed. esc exits loop
#+1:: scrollit(3000)
#+2:: scrollit(600)
#+3:: scrollit(300)
Esc:: abort()
scrollit(delay)
{
global abort := false
while (!abort)
{
Send {WheelDown}
Sleep delay
}
}
abort()
{
global abort := true
}
Your code doesn't work because by default there is only one thread per hotkey. When you do:
Loop
{
Send {WheelDown}
Sleep 100
}
You never return from this one thread so when you call it second time the hotkey will not fire and your program will continue looping in the current thread.
Jim U solved it by calling #MaxThreadsPerHotkey 2, this wouldn't have made your code work though because you don't return from your hotkey threads at all, Jim U doesn't return from the first thread only so 2 threads is enough for his solutoin to work.
An alternative solution is to use timers, the following will change the scrolling speed immediately, doesn't need any special directives and doesn't rely on Autohotkeys unique threading model.
#+1::callSetTimer(3000)
#+2::callSetTimer(600)
#+3::callSetTimer(100)
#+0::callSetTimer(600, "WheelUp")
Esc::SetTimer, scrollTimer, Off
callSetTimer(interval, key := "WheelDown") {
global currKey := key
SetTimer, scrollTimer, %interval%
scrollTimer:
send, {%currKey%}
return
}
I have this RxSwift code in swift 3
let bag:DisposeBag = DisposeBag()
var sig:Observable<Int>!
sig = Observable<Int>.interval(1.0, scheduler: MainScheduler.instance)
sig.subscribe(onNext: { (milsec) in
print("Mil: \(milsec)")
}).addDisposableTo(bag)
i run this code when button tapped, but its not print anything on console.
DisposeBag will dispose of your subscription once it goes out of scope. In this instance, it'll be right after the call to subscribe, and it explains why you don't see anything printed to the console.
Move the definition of dispose bag to the class creating the subscription and everything should work fine.
class MyViewController: UIViewController {
let bag:DisposeBag = DisposeBag()
dynamic func onButtonTapped() {
var sig:Observable<Int>!
sig = Observable<Int>.interval(1.0, scheduler: MainScheduler.instance)
sig.subscribe(onNext: { (sec) in
print("Sec: \(sec)")
}).addDisposableTo(bag)
}
}
On a side note, interval expects an interval in seconds, so it will only tick every seconds as oposed to milliseconds.
I am facing a weird case, I am using google directionsService.route. but it doesn’t sync well. Here is my code:
angular.forEach(requestArray, function(v, i) {
directionsService.route(v, function(result, status) {
var googleLeg = result.routes[0].legs[0];
// sth else...
});
});
As you can see, I am looping the location Array into the route. every time I fire the function, it will go through the requestArray first, (if we make a breakpoint on the line (var googleLeg = result.routes[0].legs[0]), it doesn’t reach there until it goes through all the requestArray.(i from 0 - length); then it will have the second loop for directionsService.route( at this time, it will reach to line(var googleLeg = result.routes[0].legs[0]); Any idea about this?
Essentially your problem is that calling a google service is an asynchronous call, and you are not guaranteed when the callback will execute. If you need to process requestArray synchronously, here is what you can do:
function start() {
// create a copy of request array
var stuff = [].slice.call(requestArray);
function continueSync() {
// stop the recursion if we have nothing left to process
if (!stuff || stuff.length == 0) return;
// grab the first item off of the stuff queue
v = stuff[0];
stuff = stuff.slice(1);
// call to google
directionsService.route(v, function(result, status) {
var googleLeg = result.routes[0].legs[0];
// sth else...
// now continue processing the rest of the stuff queue through tail recursion
continueSync();
});
}
// kick off our recursive processing
continueSync();
}
your problem is that calling a google service is an asynchronous call, you could prove to generate threads
-define(INTERVAL, 1000).
init([]) ->
Timer = erlang:send_after(?INTERVAL, self(), tick),
{ok, Timer}.
handle_info(tick, OldTimer) ->
erlang:cancel_timer(OldTimer),
io:format("Tick ~w~n", [OldTimer]),
Timer = erlang:send_after(?INTERVAL, self(), tick).
{noreplay, Timer}.
start_clock() ->
{_, Timer} = init([]),
spawn(clock, handle_info, [tick, Timer]).
My codes is as above, but the output is not what I want.
How can I integrate init() and handle_info() into the main function(start_clock)?
In the timer module, the function apply_interval(Time, Module, Function, Arguments) executes Module:Function(Arguments) every interval of Time. It takes care of spawning a process, returns a reference to allow a cancellation later.
You also can have a look at send_interval(Time, Pid, Message) in the same library.
You can also implement a simple loop like:
loop(Args,Tick) when is_integer(Tick), Tick >= 0 ->
receive
stop -> stopped
after
Tick ->
do_something(Args),
{NewArgs,NewTick} = new_args(Args,Tick),
loop(NewArgs,NewTick)
end.
it is not a realtime timer, but the function new_args(Args,Tick) can help to correct the deviation due to process scheduling.
I think you need something like this:
start_timer() ->
gen_server:start_link({local, clock}, ?MODULE, [], []).