I've just started a project that will require me to pair a Windows 10 tablet with another bluetooth device.
I decided to start with a simple windows forms app to familiarise myself with the process. I added the 32feet.NET NuGet package to my solution, and quickly had success with searching for devices and populating a listbox.
client = new BluetoothClient();
devices = client.DiscoverDevices();
if (devices.Length > 0)
{
foreach (var device in devices)
{
lstBTDevices.Items.Add(device.DeviceName);
}
}
else
{
MessageBox.Show("Unable to detect any bluetooth devices");
}
I then added an event handler so I could select a detected device and attempt to pair with it.
private void LstBTDevices_SelectedIndexChanged(object sender, EventArgs e)
{
BluetoothDeviceInfo selectedDevice = devices[lstBTDevices.SelectedIndex];
if (MessageBox.Show(String.Format("Would you like to attempt to pair with {0}?", selectedDevice.DeviceName), "Pair Device", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
if (BluetoothSecurity.PairRequest(selectedDevice.DeviceAddress, "123456"))
{
MessageBox.Show("We paired!");
}
else
{
MessageBox.Show("Failed to pair!");
}
}
}
On my Windows7 desktop PC with cheap Bluetooth 2.0 adaptor this causes a popup to appear on my phone requesting I enter the pincode. When I enter "123456" the pairing is successful.
However, this is where the problem starts. I then take my application and run it on my Windows10 tablet, and now when I select my phone it causes a popup to appear on my phone with a random 6 digit pincode, and a message that it should match what is displayed on my tablet screen, with pair/cancel buttons as the options. Pressing either button results in a fail.
Is this something i'm doing wrong? A driver not supported by 32feet.NET?
Any advice would be much appreciated.
UPDATE: The comment from bare_metal has helped me get a bit further
I added a BluetoothWin32Authentication event handler and added a button to initiate an SSP pairing:
EventHandler<BluetoothWin32AuthenticationEventArgs> authHandler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(handleAuthRequests);
BluetoothWin32Authentication authenticator = new BluetoothWin32Authentication(authHandler);
private void btnPairSSP_Click(object sender, EventArgs e)
{
BluetoothDeviceInfo selectedDevice = devices[lstBTDevices.SelectedIndex];
if (MessageBox.Show(String.Format("Would you like to attempt to pair with {0}?", selectedDevice.DeviceName), "Pair Device", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
Task t = new Task(PairBluetoothTask);
t.Start();
}
}
private void PairBluetoothTask()
{
BluetoothDeviceInfo selectedDevice = devices[lstBTDevices.SelectedIndex];
if (BluetoothSecurity.PairRequest(selectedDevice.DeviceAddress, null))
{
MessageBox.Show("We paired!");
}
else
{
MessageBox.Show("Failed to pair!");
}
}
private void handleAuthRequests(object sender, BluetoothWin32AuthenticationEventArgs e)
{
switch (e.AuthenticationMethod)
{
case BluetoothAuthenticationMethod.Legacy:
MessageBox.Show("Legacy Authentication");
break;
case BluetoothAuthenticationMethod.OutOfBand:
MessageBox.Show("Out of Band Authentication");
break;
case BluetoothAuthenticationMethod.NumericComparison:
if(e.JustWorksNumericComparison == true)
{
MessageBox.Show("Just Works Numeric Comparison");
}
else
{
MessageBox.Show("Show User Numeric Comparison");
if (MessageBox.Show(e.NumberOrPasskeyAsString, "Pair Device", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
e.Confirm = true;
}
else
{
e.Confirm = false;
}
}
break;
case BluetoothAuthenticationMethod.PasskeyNotification:
MessageBox.Show("Passkey Notification");
break;
case BluetoothAuthenticationMethod.Passkey:
MessageBox.Show("Passkey");
break;
default:
MessageBox.Show("Event handled in some unknown way");
break;
}
}
When I initiate pairing from my phone, this works fine, the event is triggered, the message box pops and pairing is successful.
However when I initiate pairing from the tablet, the event handler is never triggered, so pairing fails.
I believe the problem here is that the 32feet library is built around legacy pairing, so that you either need to know the pin of the device you are connecting to, or you supply it with a null to get a popup window to enter a pin. That dialog may not have made it through to the new version of windows -
Not sure on this, but the documentation for the native function that the 32feet library wraps, says to call another method if developing for newer than Vista.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa362770(v=vs.85).aspx
From my research browsing through the decompiled sources of 32feet, it may look like 32feet doesn't support SSP, just others - but that may only be that the supplied bluetooth stack implementations need updating - or you need to create your own - again I am not sure.
You may want to look into Microsoft supplied libraries for .NET instead of this 3rd party, I was able to use their example from Github to successfully connect and pair with all my devices.
https://msdn.microsoft.com/en-us/library/windows/apps/mt168401.aspx
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing/cs
Related
A basic overview. I am sending serial data from an Arduino Due to WPF application. Up until now this has all been working perfectly. Today I implemented a loop into the Arduino code that looks for a "Y" (ascii 89) in the serial port, if received it leaves the loop and returns back into what I am calling offline mode and stops sending over data, via online = false.
Now what is strange about this is that...
It was working fine before this loop so it must be something to do with trying to resend new data once it has left the 'online loop'.
It works perfectly from the Arduino serial monitor, which suggests it's a WPF problem, although the code hasn't changed on the upload section.
The code for both of these programmes is pretty big so I will try and keep it concise whilst providing all the information necessary.
void loop() {
// Check to see if the testbench is in offline mode and run the respective code.
if (Online == false) {
OfflineMode();
}
// Check to see if the testbench is in online mode and run the respective code.
if (Online == true) {
OnlineMode();
}
}
void OfflineMode() {
while (Serial.available())
processlncomingByte(Serial.read());
}
I then have switch cases to handle incoming settings - I know this works fine as it will also upload after the Arduino is reset.
void processlncomingByte (const byte c) {
if (isdigit (c)) {
currentValue *= 10;
currentValue += c - '0';
} else {
// end of digit
// The end of the number signals a state change
handlePreviousState ();
// set the new state, if we recognize it
switch (c) {
case 'A':
state = GOT_A;
break;
etc...
Online Mode
void OnlineMode() {
CheckForStop();
SendSerialData();
}
void CheckForStop() {
//Serial.println("...");
if (Serial.available() > 0) {
//Serial.println("getting something");
ch = (char)Serial.read();
inputString = ch;
if (ch == 89) {
//Serial.end();
Online = false;
//Serial.begin(9600);
exit;
//return;
}
} else
delay(5);
}
SendSerialData() consists of just a range of serial.print, outputting into one large string for WPF to handle.
Here is a screenshot of the serial monitor working
As you will see from the link above the monitor spits out a load of data, stops when I send a Y and finally I send a Q to 'question' whether the Arduino is ready to receive settings and S signifies a Yes. Great stuff it works!
However as you can see from the link below this isn't the case in WPF. Sorry, I can only upload 2 images at the moment so had to combine them.
Combo of screenshots
Here is the loop it is currently getting stuck in
private bool checkArduinoisReady() {
Stopwatch Uploadtimer = new Stopwatch();
if (!myPort.IsOpen)
return false;
// Debug.Print("port is ready to be opened");
string tempdata;
Uploadtimer.Start();
myPort.DiscardInBuffer();
Start:
myPort.WriteLine("Q" + Environment.NewLine);
Debug.Print("sent Q");
tempdata = myPort.ReadExisting();
Debug.Print("tempdata_" + tempdata.ToString());
if (Uploadtimer.ElapsedMilliseconds > 5000)
return false;
if (tempdata.Contains("S"))
return true;
else
goto Start;
}
And on a separate page this is how I am stopping the incoming data.
private void StopTest(object sender, RoutedEventArgs e) {
MessageBoxResult StopConfirm = MessageBox.Show("Are you sure you want to stop the test?", "Stop the test", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (StopConfirm == MessageBoxResult.Yes) {
Timer.Stop();
Debug.Print("Timer Stopped");
myPort.DiscardInBuffer();
Start:
for (int i = 0; i < 100; i++) {
myPort.WriteLine("Y");
}
string tempData = myPort.ReadExisting();
Debug.Print("Checking...");
Debug.Print("tempData_" + tempData);
if (string.IsNullOrWhiteSpace(tempData)) {
Debug.Print("Its null!!");
comments_textbox.Text = comments_textbox.Text + "Test Aborted";
MessageBoxResult SaveCurrentData = MessageBox.Show("Would you like to save the data collected up until this point?", "Save", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (SaveCurrentData == MessageBoxResult.Yes) {
SaveFile();
}
if (SaveCurrentData == MessageBoxResult.No) {
myPort.Close();
NavigationService.Navigate(new Uri("testSettings.xaml", UriKind.RelativeOrAbsolute));
}
} else {
Debug.Print("Still going...");
goto Start;
}
}
}
The biggest stumbling block for me is why this works over the serial monitor but not within the application. And it also works as soon as I reset the Arduino. I have also tried the resetFunc() in Arduino but this didn't help either.
Thanks in advance.
It turns out i still had a resetFunc() in my switch case which was preventing the serial monitor from continuing to send data!
Is it possible to suppress the windows global shortcuts while recording keypresses ?
I have a Windows Form application written in c#, and using this library to record keypresses to use later in macros. Now when I record the key combinations that are used by Windows (i.e. L Control + Win + Right Arrow to change virtual desktop on Win 10), I'd like my app to record it but avoid windows actually using it while I record which is quite annoying.
I have a checkbox to enable key capturing, on click event
m_KeyboardHookManager.KeyDown += HookManager_KeyDown;
the HookManager_KeyDown is simply like this
private void HookManager_KeyDown(object sender, KeyEventArgs e)
{
Log(string.Format("KeyDown \t\t {0}\n", e.KeyCode));
string [] sArr = new string [2];
if (keyBindingArea1.Text != "")
{
sArr[0] = keyBindingArea1.Text;
sArr[1] = string.Format("{0}", e.KeyCode);
keyBindingArea1.Text = string.Join("+", sArr);
}
else
{
keyBindingArea1.Text = string.Format("{0}", e.KeyCode);
}
}
which display the key combination in a comboText control. (This code is taken directly from the demo attached to the package.
Now the recording work well if for instance I press L Control + Win, then I release the keys and press the third one (i.e. Right Arrow), this will not trigger Windows shortcuts but it is quite annoying to have it work like that.
Appreciate any help. Thanks
Try to use e.Handled property of the event. If you set it to true it will terminate key procesing chain. As a rule oher applications in the processing chain will not get it. I am not sure it is going to work for such a low level windows staff as virtual desktop switch.
private void OnKeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
bool isThirdKey = //Some state evaluation to detect the third key was pressed
if (isThirdKey) e.Handled = true;
}
I am trying to create an app for learning purpose in which one windows phone 8 user sends the text and other user receives it. And the text is shared through NFC. But the problem is the other user is not able to receive the text.
Here is the code=>
Receiver's Code:
ProximityDevice device;
long subscribedMessageId;
private void receive_Click(object sender, RoutedEventArgs e)
{
device = ProximityDevice.GetDefault();
if (device != null)
{
subscribedMessageId = device.SubscribeForMessage("Windows.SampleMessage", messageReceivedHandler);
}
}
private void messageReceivedHandler(ProximityDevice sender, ProximityMessage message)
{
rtextbox.Text = message.DataAsString;
device.StopSubscribingForMessage(subscribedMessageId);
}
Sender's Code:
ProximityDevice device;
long publishedMessageId;
private void send_Click(object sender, RoutedEventArgs e)
{
device = ProximityDevice.GetDefault();
device.StopPublishingMessage(publishedMessageId);
if (device != null)
{
publishedMessageId = device.PublishMessage("Windows.SampleMessage", textbox1.Text);
textbox1.Text = "";
}
}
Both the codes are present on different page. Code is executed when the user clicks on send or receive button respectively.
I am new to NFC so any help will be appreciated.
Unfortunately, NFC gets complicated. There's quite a bit of plumbing involved to handle peer-to-peer communication seamlessly. It's far too much to put into an answer here on the site, so I will have to resort to links.
You can check out this Nokia article and project to work through your understanding of the plumbing and get an application going that will exchange text. http://developer.nokia.com/Resources/Library/Lumia/#!code-examples/nfc-talk.html
Then, if you want to take it up a notch, you can work through this article to upgrade your app to allow image transfer functionality as well. http://developer.nokia.com/Community/Wiki/Transfer_an_Image_with_NFC
I have a program that is similar to an ATM application. I use my android device a the Keypad. No problem with transmitting data from phone to my C# program. I use threading. I have a problem on how to really "start" the ATM application.
The only input device is the android device. I will not use computer keyboard or anything. So once the program is shown, the first thing is that the program will ask what kind of transaction is it.
private void FrontPage_Shown(object sender, EventArgs e)
{
Ask_Transaction();
}
and inside that... (Edited part)
public void Ask_Transaction()
{
string decoded_input = "";
decoded_input = KT.CheckPress(input); //"input" is the data from the arduino. the checkpress will decode it.
do
{
try
{
//input = serialPort.ReadLine();
switch (KT.CheckPress(input))
{
case "S5": //Card;
break;
case "S6": //Cardless
{
PF.Format_Cardless();
AskLanguage(); //if cardless, it will now ask the language. Once again, another input from serial is needed
}
break;
case "Cancel": PF.Format_TransactionCancelled();
break;
default:
break;
}
}
catch
{
//To catch ReadTimeout after 6 seconds
//"You do not respond to the alloted time.."
}
}
while (decoded_input != "S5"
|| decoded_input != "S6"
|| decoded_input != "Cancel");
}
my problem is that when I try to loop Ask_Transaction until I get the correct inputs (S5 or S6 or cancel) using a do-while loop, my program is lagging and eventually crashing. No errors displaying.
EDIT:
Of course we cannot assure that the user will input the correct key. And usually when you click just numbers on the keypad, ATM program will not notify you at first. It will just wait for possible correct inputs. Also, if the user enters S6, the program will now ask another input using those keypad numbers s5 and s6. the problem is that the program is not "continuous". Any kind of help will be appreciated.
I am using the Microsoft.DirectX and Microsoft.DirectX.Direct3D references to do some drawing on my form. While I am running the program and the user presses CTRL ALT DEL in Windows XP and brings up the "Windows Security" form, when returning back to the Form, a DeviceLostException is thrown and when trying to handle this exception there seems to be no way to get it back.
I have done a little research into the matter and have tried several coding solutions.
try
{
_d3ddevice.Present();
}
catch
{
DeviceLost = true;
}
if (DeviceLost)
{
AttemptRecovery();
}
this.Invalidate();
ReadKeyboard();
base.OnPaint(e);
}
private void AttemptRecovery()
{
try
{
_d3ddevice.TestCooperativeLevel();
}
catch (DeviceLostException)
{
Application.Exit();
}
catch (DeviceNotResetException)
{
try
{
_d3ddevice.Reset(_params);
DeviceLost = false;
InitGraphics();
CameraPositioning();
VertexDeclaration();
IndicesDeclaration();
}
catch (DeviceLostException)
{
}
}
}
When the program calls TestCooperativeLevel(), it said online if it catches the DeviceLostException again that there is no point in trying to reset the device.
What can I do to reset the device and continue drawing in my form?
2 things in 4 points :
You shouldn't use Microsoft.DirectX, it's deprecated since a long, long time. Check out SlimDX or SharpDX instead.
In order to re-create your device, you first have to wait until the device can be restored
When the device can be restored, you have to free all video-memory objects, and recreate them.
You call the Reset method.