How to connect Cortana commands to custom scripts? - scripting

This may be a little early to ask this, but I'm running Windows 10 Technical Preview Build 10122. I'd like to set up Cortana to have custom commands. Here's how she works:
Hey Cortana, <she'll listen and process this command>
Microsoft will process the command and if there isn't anything for it, she'll just search the input on bing. However, I'd like to be able to say something like, just for example
Hey Cortana, I'm going to bed now
And have the input I'm going to bed now trigger run a batch script, a VBScript, a command, or any some sort some of custom response that basically does the following.
C:\> shutdown -s
Is there a way to set up a predefined custom commands for Cortana?
Update:
I created this basic YouTube tutorial and this more advanced one with a corresponding GitHub repo based on talkitbr's excellent and very helpful answer below.
At first his answer was beyond my understanding so I decided to break it down in a bit more detail for future users like myself.

You can create commands for Cortana to listen for.
These commands need to be described in a XML file called Voice Command Definitions or VCD.
Here's an example:
<?xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
<CommandSet xml:lang="en-us" Name="HomeControlCommandSet_en-us">
<CommandPrefix>HomeControl</CommandPrefix>
<Example>Control alarm, temperature, light and others</Example>
<Command Name="Activate_Alarm">
<Example>Activate alarm</Example>
<ListenFor>[Would] [you] [please] activate [the] alarm [please]</ListenFor>
<ListenFor RequireAppName="BeforeOrAfterPhrase">Activate alarm</ListenFor>
<ListenFor RequireAppName="ExplicitlySpecified">Activate {builtin:AppName} alarm</ListenFor>
<Feedback>Activating alarm</Feedback>
<Navigate />
</Command>
...
</CommandSet>
</VoiceCommands>
After create this definition, you need to register it at App Startup:
protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
...
// Install the VCD
try
{
StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(#"HomeControlCommands.xml");
await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("There was an error registering the Voice Command Definitions", ex);
}
}
An then override the App.OnActivated method to handle when the events are triggered:
protected override void OnActivated(IActivatedEventArgs e)
{
// Handle when app is launched by Cortana
if (e.Kind == ActivationKind.VoiceCommand)
{
VoiceCommandActivatedEventArgs commandArgs = e as VoiceCommandActivatedEventArgs;
SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;
string voiceCommandName = speechRecognitionResult.RulePath[0];
string textSpoken = speechRecognitionResult.Text;
IReadOnlyList<string> recognizedVoiceCommandPhrases;
System.Diagnostics.Debug.WriteLine("voiceCommandName: " + voiceCommandName);
System.Diagnostics.Debug.WriteLine("textSpoken: " + textSpoken);
switch (voiceCommandName)
{
case "Activate_Alarm":
System.Diagnostics.Debug.WriteLine("Activate_Alarm command");
break;
The tutorial shows the complete code [web archive].
After you do all of this, you can call your batch scripts using ProcessStartInfo or System.Diagnostics.Process.Start.
Also, if you are interested in responding to the user through Cortana window, check this post regarding Cortana in background [web archive].

What you can do is write a .bat file and add a shortcut to the file to the Folder: C:\ProgramData\Microsoft\Windows\Start Menu\Programs
you can name the shortcut whatever you want and trigger the shutdown by saying: "Hey Cortana open/start [shortcut name]".
Make sure that Cortana only listens to you to not get "pranked".

Related

StimulusJS - how to ensure controller has all the necessary targets?

I'm trying to find a way to make my Stimulus controller more robust and maintainable by checking that all the required targets are present. If something is missing, I would like it to fail fast and loud.
Below is what I'm using so far:
export default class extends Controller {
static targets = ['name'];
connect() {
if (!that.hasNameTarget) {
throw new Error('expected to find name target');
}
}
}
Perhaps someone knows of a more idiomatic/clean solution?
Option 1 - use the Stimulus debugger tooling
Stimulus has a debug mode that logs out info/warnings etc for Stimulus controllers. You can enable this by stimulus.debug = true;
You can call this in your own controllers via this.application.logDebugActivity() - see https://github.com/hotwired/stimulus/blob/main/src/core/application.ts#L95
export default class extends Controller {
static targets = ['name'];
connect() {
if (!that.hasNameTarget) {
this.logDebugActivity(this.identifier, 'error', { message: 'target missing'});
throw new Error('expected to find name target');
}
}
}
Option 2 - Use the window.onerror callback
If you keep your current code where an error is thrown, Stimulus will not 'break' anything where possible as all calls within Stimulus use try/catch.
However, you can ensure that your error does something 'loud' by creating a onerror function.
See docs - https://stimulus.hotwired.dev/handbook/installing#error-handling
See an example where this can be used for something like Sentry https://blog.sentry.io/2016/01/04/client-javascript-reporting-window-onerror
You could also just be really loud and block the UI with something similar to this.
window.onerror = (message, url, lineNo, columnNo, error) => {
document.body.style.backgroundColor = 'red';
window.alert(message);
}
Reminders
Remember to only enable these debugging features in local development, you can do this with something like Webpack environment variables but this will be different depending on your tooling.
In production though you may want to push your onerror calls to whatever logging infrastructure you have.
stimulus.debug mode is quite 'noisy' and may be too much information, depending on your set up.

Custom command to go back in a process instance (execution)

I have a process where I have 3 sequential user tasks (something like Task 1 -> Task 2 -> Task 3). So, to validate the Task 3, I have to validate the Task 1, then the Task 2.
My goal is to implement a workaround to go back in an execution of a process instance thanks to a Command like suggested in this link. The problem is I started to implement the command by it does not work as I want. The algorithm should be something like:
Retrieve the task with the passed id
Get the process instance of this task
Get the historic tasks of the process instance
From the list of the historic tasks, deduce the previous one
Create a new task from the previous historic task
Make the execution to point to this new task
Maybe clean the task pointed before the update
So, the code of my command is like that:
public class MoveTokenCmd implements Command<Void> {
protected String fromTaskId = "20918";
public MoveTokenCmd() {
}
public Void execute(CommandContext commandContext) {
HistoricTaskInstanceEntity currentUserTaskEntity = commandContext.getHistoricTaskInstanceEntityManager()
.findHistoricTaskInstanceById(fromTaskId);
ExecutionEntity currentExecution = commandContext.getExecutionEntityManager()
.findExecutionById(currentUserTaskEntity.getExecutionId());
// Get process Instance
HistoricProcessInstanceEntity historicProcessInstanceEntity = commandContext
.getHistoricProcessInstanceEntityManager()
.findHistoricProcessInstance(currentUserTaskEntity.getProcessInstanceId());
HistoricTaskInstanceQueryImpl historicTaskInstanceQuery = new HistoricTaskInstanceQueryImpl();
historicTaskInstanceQuery.processInstanceId(historicProcessInstanceEntity.getId()).orderByExecutionId().desc();
List<HistoricTaskInstance> historicTaskInstances = commandContext.getHistoricTaskInstanceEntityManager()
.findHistoricTaskInstancesByQueryCriteria(historicTaskInstanceQuery);
int index = 0;
for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
if (historicTaskInstance.getId().equals(currentUserTaskEntity.getId())) {
break;
}
index++;
}
if (index > 0) {
HistoricTaskInstance previousTask = historicTaskInstances.get(index - 1);
TaskEntity newTaskEntity = createTaskFromHistoricTask(previousTask, commandContext);
currentExecution.addTask(newTaskEntity);
commandContext.getTaskEntityManager().insert(newTaskEntity);
AtomicOperation.TRANSITION_CREATE_SCOPE.execute(currentExecution);
} else {
// TODO: find the last task of the previous process instance
}
// To overcome the "Task cannot be deleted because is part of a running
// process"
TaskEntity currentUserTask = commandContext.getTaskEntityManager().findTaskById(fromTaskId);
if (currentUserTask != null) {
currentUserTask.setExecutionId(null);
commandContext.getTaskEntityManager().deleteTask(currentUserTask, "jumped to another task", true);
}
return null;
}
private TaskEntity createTaskFromHistoricTask(HistoricTaskInstance historicTaskInstance,
CommandContext commandContext) {
TaskEntity newTaskEntity = new TaskEntity();
newTaskEntity.setProcessDefinitionId(historicTaskInstance.getProcessDefinitionId());
newTaskEntity.setName(historicTaskInstance.getName());
newTaskEntity.setTaskDefinitionKey(historicTaskInstance.getTaskDefinitionKey());
newTaskEntity.setProcessInstanceId(historicTaskInstance.getExecutionId());
newTaskEntity.setExecutionId(historicTaskInstance.getExecutionId());
return newTaskEntity;
}
}
But the problem is I can see my task is created, but the execution does not point to it but to the current one.
I had the idea to use the activity (via the object ActivityImpl) to set it to the execution but I don't know how to retrieve the activity of my new task.
Can someone help me, please?
Unless somethign has changed in the engine significantly the code in the link you reference should still work (I have used it on a number of projects).
That said, when scanning your code I don't see the most important command.
Once you have the current execution, you can move the token by setting the current activity.
Like I said, the code in the referenced article used to work and still should.
Greg
Referring the same link in your question, i would personally recommend to work with the design of you your process. use an exclusive gateway to decide whether the process should end or should be returned to the previous task. if the generation of task is dynamic, you can point to the same task and delete local variable. Activiti has constructs to save your time from implementing the same :).

Windows Phone - developing a caller ID app

I'm not a Windows Phone developer myself, so I apologize in advance for my lack of knowledge.
One of the products we offer our customers is a caller ID app. The software does the following:
Detect incoming calls and get the caller number
If the number isn't found in contacts, do a name search on our server (HTTP Get request to an XML interface)
If a name is found from our server, display it on screen while the phone is ringing
(Other stuff, such as storing results to contacts etc.)
We've implemented the app on Android and Symbian and it works perfectly. I'd like to know if this type of application is even possible on a Windows Phone. According to our subcontractor, this hasn't been the case with previous versions. I'd like to know if this is really true and if things have changed in WP8.
My questions:
Can an application be run as a background process?
Do incoming calls fire events that can be detected by the background process?
Can you get the caller phone number from an incoming call in real time?
Can you perform the search in the background during an incoming call?
Can you display anything on the screen during an incoming call?
From what I've googled, I've only found mentions about the "Obscured" event, nothing about a "Call" event or similar. This isn't very promising, but I'd like to hear from actual developers.
Yes (look up "Background Agents," http://www.jeffblankenburg.com/2011/11/25/31-days-of-mango-day-25-background-agents/).
You should start there and then perform more independent research related to the spec of your app.
Per Jeff's article:
Launch Visual Studio and create a new project. Under Silverlight for Windows Phone, select Windows Phone Application. Name it “MyAgentApp”.
You’ve now created the main application. It will be responsible for two things:
1) Having a live tile that the Background Agent can update with information
2) Starting and stopping the Background Agent
The Background Agent itself must live in its own special project. Add a new project to your solution, selecting Windows Phone Scheduled Task Agent. Name it MyAgent. This project will contain your custom code that will run in the background and update the live tile.
Finally, and this is important, go to the MyAgentApp project and add a project reference to MyAgent. This will allow you to register your agent from within the application. Also, notice the entry this automatically created in WMAppManifest.xml:
<Tasks>
<DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
<ExtendedTask Name="BackgroundTask">
<BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="MyAgent" Source="MyAgent" Type="MyAgent.ScheduledAgent" />
</ExtendedTask>
</Tasks>
Now it’s time to actually wire everything up. Open MainPage.xaml and add two buttons, one for starting the agent, and the other for stopping the agent:
<StackPanel VerticalAlignment="Center">
<Button Content="Start Background Agent"
Click="StartButton_Click"/>
<Button Content="Stop Background Agent"
Click="StopButton_Click"/>
</StackPanel>
In MainPage.xaml.cs, wire up the buttons to start and stop the agent:
private const string TASK_NAME = "MyAgent";
private void StartButton_Click(object sender, RoutedEventArgs e)
{
StartAgent();
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
StopAgentIfStarted();
}
private void StartAgent()
{
StopAgentIfStarted();
PeriodicTask task = new PeriodicTask(TASK_NAME);
task.Description = "This is our custom agent for Day 25 - Background Agents";
ScheduledActionService.Add(task);
#if DEBUG
// If we're debugging, attempt to start the task immediately
ScheduledActionService.LaunchForTest(TASK_NAME, new TimeSpan(0, 0, 1));
#endif
}
private void StopAgentIfStarted()
{
if (ScheduledActionService.Find(TASK_NAME) != null)
{
ScheduledActionService.Remove(TASK_NAME);
}
}
Notice that to create our custom agent, we are creating a new PeriodicTask. We then use the name as an identifier when finding and stopping the agent. Notice also that we specified PeriodicTask.Description – this is a required field and will appear in Settings | Background Tasks under the name of our application.
In the MyAgent project, open ScheduledAgent.cs and add the following code:
protected override void OnInvoke(ScheduledTask task)
{
UpdateAppTile(GetLastUpdatedTimeMessage());
}
private string GetLastUpdatedTimeMessage()
{
return string.Format("Last Updated: {0}", DateTime.Now);
}
private void UpdateAppTile(string message)
{
ShellTile appTile = ShellTile.ActiveTiles.First();
if (appTile != null)
{
StandardTileData tileData = new StandardTileData
{
BackContent = message
};
appTile.Update(tileData);
}
}
ScheduledAgent has one important method to override – OnInvoke. This is where your agent will execute its background task. If your task is complete and you no longer need your agent to run, you can call NotifyComplete() to signal that the task completed successfully or Abort() to signal that you are cancelling your task. To keep the task running at an interval, simply do not call either, which is what we are doing here.

adobe air command line parameters

I am using parameters from the command line which come in through the invoke handler of my WindowedApplication. I used to build using the excellent Flash Develop, we are now using Flash Builder 4.
I would like to know where do I enter these parameters in Flash Builder 4 so I can test them while debugging my app.
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke);
function onInvoke(e:InvokeEvent):void
{
trace('onInvoke', e.arguments);
}
Answering this question for Spark Application container. The WindowedApplication class allows you to do:
<s:WindowedApplication
invoke="onInvoke()"
>
but the Application container does not, so instead, you need to do this:
<s:Application
...
preinitialize="onPreinitialize()"
>
<fx:Script>
<![CDATA[
private function onPreinitialize():void
{
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke);
}
private function onInvoke(e:InvokeEvent):void
{
// e.arguments is an array containing the command line args
}
]]>
</fx:Script>

Silverlight 4 Asynchronous Issue

I am creating an application in Silverlight 4. The first screen the user comes in contact with is the Login screen (Login.xaml). I have written the following code in Login.xaml.cs file.
private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
//first validate if the user is authorised for this application
if (this.ValidateEntry())
{
if (UserAuthenticationBL.AuthenticateUser(txtUserName.Text.Trim(), txtPassword.Password.Trim()))
{
//since the user is authenticated we will show the dashboard screen
this.Content = new MainPage();
}
else
{
this.ShowErrorMessage("Invalid username or password");
txtUserName.Focus();
}
}
}
My problem is that the code gets executed before i get the data in the AuthenticateUser method. The code immediately comes down to the "Invalid username or password" and the list is loaded after all the execution on the xaml page has finished.
I know there is something going wrong with the Asynchronous thingi...and i also know i need to put an event to know when the loading has completed........
but i dont know how to go about it!!!
can someone please put some light on this issue...
thank you.
If I understood it right, your AuthenticateUser method is running async, right?
You have to define a callback to the AuthenticateUserComplete event and run the method in the button submit event. In the callback write this if/else clause, then it will be called once the asynchronous method was completed.
Just one question, why are you doing asynchronously if your behavior should be synchronous? (You have to get the answer before deciding what to do).
This http://msdn.microsoft.com/en-us/library/aa719598%28VS.71%29.aspx
may be helpful :)
Oscar