GetDeviceInfo XKB request through XCB yields BadAccess error - rust

I am trying to use the XKB extension to XCB to capture keyboard input. The particular implementation that I'm writing is in rust, however the erroneous part of the code is mostly just calls through FFI. My goal is to be able to process keyboard events, such as when a key is pressed, released, etc., and to be able to convert the keycodes into unicode. Currently I am trying to get this example from the libxkbcommon quick guide working.
Below is the code I tried:
let (conn, screen_num) = Connection::connect(None)?;
// Other code...
let raw_conn = conn.get_raw_conn() as *mut xkbcommon_sys::xcb_connection_t;
let context = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS) };
if context.is_null() {
return Err(Error::XkbContextInit);
}
let device_id = unsafe { xkb_x11_get_core_keyboard_device_id(raw_conn) };
// This branch is taken
if device_id == -1 {
unsafe { xkb_context_unref(context); }
return Err(Error::XkbGetCoreKbDev);
}
I expected to be able to get the device ID of the core keyboard, however instead the function returned -1, signaling an error.
After some experimenting and digging around, I found that the xkb_x11_get_core_keyboard_device_id function was specifically failing on this request, which used XCB_XKB_ID_USE_CORE_KBD as the value for the device spec. Since I don't get much error information from this function, I translated the request to the X server into rust, and got the following error:
// Output from debugging the returned error enum
Protocol(
X(
Access(
RequestError {
response_type: 0,
error_code: 10,
sequence: 3,
bad_value: 2003,
minor_opcode: 1,
major_opcode: 130,
pad: 1
}
)
)
)
I also tried some of the other values for the device spec listed here, but received the same error.
Unsure whether this was an issue with the X server, I tried it on my installation of Kali as well as an Ubuntu 20.04 VM, both of which yielded the same error (although with different values for the bad_value field). Furthermore, any time I use XCB_XKB_ID_USE_CORE_KBD where a device spec is required, I get this error. I'm not really sure what could be causing this issue. This seems to be specifically related to XKB since I am also using XCB to capture the screen, and I have not had any errors with that so far. Any help or guidance would be appreciated.

After searching around for a while, I found this post which linked to some documentation which made me realize that I was never setting up the XKB extension. Adding the following code fixed the issue:
let res = unsafe {
xkb_x11_setup_xkb_extension(
raw_conn,
MAJOR_VERSION as u16,
MINOR_VERSION as u16,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut()
)
};
if res == 0 {
return Err(Error::XkbInit);
}

If you are using the xcb and xkbcommon crates, they have an example using the (currently) beta versions of the crates that do this using the API instead of unsafe functions:
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let device_id = xkb::x11::get_core_keyboard_device_id(&connection);
let keymap = xkb::x11::keymap_new_from_device(
&context,
&connection,
device_id,
xkb::KEYMAP_COMPILE_NO_FLAGS,
);
let state = xkb::x11::state_new_from_device(&keymap, &connection, device_id);
https://github.com/rust-x-bindings/toy_xcb/blob/master/src/keyboard.rs

Related

Can I get nft metadata from the <AccountInfo> address in solana rust program?

I've noticed that metaplex got API for platforms like JS, iOS, Android and all of them are documented great, except RUST :)
For example all of apis above got something like getNftByMint with output of mine nft data with all metadata inside
But checking all the rust/solana/anchor crates and docs I didn't find any way how to get metadata from metadataAccount right in the rust program, in instance to check some params of some nfts and do something)
The only way I found is below, but even if I tried to mitigate this error adding match and so on, still I got the same error message, But without from_account_info this error dissapears.
In rs program i got:
pub fn get_metadata_by_pubkey(ctx: Context<GetMetadataByPubkey>) -> Result<()> {
let account = ctx.accounts.metadata_pubkey.to_account_info();
let metadata: Metadata = Metadata::from_account_info(&account)?;
...
And in ts file:
it("Is get_metadata_by_pubkey", async () => {
const pk: PublicKey = new PublicKey("<public key of my nft's metadata account>");
await program.methods.getMetadataByPubkey().accounts({
metadataPubkey: pk
}).rpc();
});
And I got this error, after running anchor test:
Error: failed to send transaction: Transaction simulation failed:
Error processing Instruction 0: Program failed to complete
from_account_info is the correct way of doing it. Here is an example of a program that uses it https://github.com/Bonfida/dex-v4/blob/main/program/src/processor/create_market.rs#L154
However, you need to make sure the metadata account is initialized before trying to deserialize, which can be done with something like accounts.token_metadata.data_len() != 0

How to call contract's method from crate

I need to call the contract's method from my Indexer. Now I use tokio::process and near-cli written on NodeJs. It looks soundless, and I would like to do that from Rust.
Recommended way
NEAR JSON-RPC Client RS is the recommended way to interact with NEAR Protocol from within the Rust code.
Example from the README
use near_jsonrpc_client::{methods, JsonRpcClient};
use near_jsonrpc_primitives::types::transactions::TransactionInfo;
let mainnet_client = JsonRpcClient::connect("https://archival-rpc.mainnet.near.org");
let tx_status_request = methods::tx::RpcTransactionStatusRequest {
transaction_info: TransactionInfo::TransactionId {
hash: "9FtHUFBQsZ2MG77K3x3MJ9wjX3UT8zE1TczCrhZEcG8U".parse()?,
account_id: "miraclx.near".parse()?,
},
};
// call a method on the server via the connected client
let tx_status = mainnet_client.call(tx_status_request).await?;
println!("{:?}", tx_status);
In the examples folder of the repo, you will find different use cases, and hopefully, you'll find yours there as well.
near-jsonrpc-client-rs is the best option.
Alternative way
NB! This way is using non-documented APIs. It is not recommended way, because using these assumes you will dig into the code and find out how to use it by yourself.
If you're using the NEAR Indexer Framework you're literally running a nearcore node which includes:
JSON RPC server
ClientActor and ViewClient
Based on the kind of call you need to perform to your contract: change method or view method, you can use ClientActor or ViewClient.
ViewClient example
Code is for understanding the concept, not a working example.
let indexer = near_indexer::Indexer::new(indexer_config);
let view_client = indexer.client_actors().0;
let block_response = view_client
.send(query)
.await
.context("Failed to deliver response")?
.context("Invalid request")?;
You can find the usage in NEAR Indexer for Explorer starting from here
ClientActor example
ClientActor is used to send a transaction. I guess here's a good starting point to look for ClientActor example.
async fn send_tx_async(
&self,
request_data: near_jsonrpc_primitives::types::transactions::RpcBroadcastTransactionRequest,
) -> CryptoHash {
let tx = request_data.signed_transaction;
let hash = tx.get_hash().clone();
self.client_addr.do_send(NetworkClientMessages::Transaction {
transaction: tx,
is_forwarded: false,
check_only: false, // if we set true here it will not actually send the transaction
});
hash
}

Some errors E0425 & E0599 write_fmt

mod loginfo{
use std::io::Error;
use chrono::prelude::*;
use std::io::prelude::*;
use std::fs::OpenOptions;
const LOG_SYS :&'static str = "log.txt";
const LOG_ERR :&'static str = "log_error.txt";
pub fn set_log_error(info: String)->Result<(), String>{
let mut handler = OpenOptions::new().append(true)
.open(LOG_ERR);
if handler.is_err(){
create_file(LOG_ERR.to_owned()).unwrap();
set_log_error(info).unwrap();
}
if let Err(_errno) = handler.write_fmt(
format_args!("{:?}\t{:?} ->[Last OS error({:?})]\n",
Utc::now().to_rfc2822().to_string(), info,
Error::last_os_error()) ){
panic!(
"\nCannot write info log error\t Info\t:{:?}\n",
Error::last_os_error());
}
Ok(())
}
pub fn set_log(info: String)->Result<(), String>{
let mut handler = OpenOptions::new().append(true)
.open(LOG_SYS);
if handler.is_err(){
set_log_error("Cannot write info log".to_owned())
.unwrap();
}
if let Err(_errno) = handler.write_fmt(
format_args!("{:?}\t{:?}\n",
Utc::now().to_rfc2822().to_string(), info)){
set_log_error("Cannot write data log file".to_owned())
.unwrap();
}
Ok(())
}
pub fn create_file(filename : String)->Result<(), String>{
let handler = OpenOptions::new().write(true)
.create(true).open(filename);
if handler.is_err(){
panic!(
"\nCannot create log file\t Info\t:{:?}\n",
Error::last_os_error());
}
Ok(())
}
}
When compiling, I get the following errors, "error[E0599]: no method named write_fmt found for enum std::result::Result<std::fs::File, std::io::Error> in the current scope --> src/loginfo.rs:19:38`"
but despite using the right imports, I still get the same errors. Is this due to a bad implementation of the module?
Thank you in advance for your answers and remarks?
+1 #Masklinn Ok I think I understand it would be easier to just write
pub fn foo_write_log( info: String){
let mut handler = OpenOptions::new().append(true)
.create(true).open(LOG_SYS).expect("Cannot create log");
handler.write_fmt(
format_args!("{:?}\t{:?} ->[Last OS error({:?})]\n",
Utc::now().to_rfc2822().to_string(), info,
Error::last_os_error())).unwrap();
}
but despite using the right imports, I still get the same errors. Is this due to a bad implementation of the module?
Kind-of? If you look at the type specified in the error, handler is a Result<File, Error>. And while io::Write is implemented on File, it's not implemented on Result.
The problem is that while you're checking whether handler.is_err() you never get the file out of it, nor do you ever return in the error case. Normally you'd use something like match or if let or one of the higher-order methods (e.g. Result::map, Result::and_then) in order to handle or propagate the various cases.
And to be honest the entire thing is rather odd and awkward e.g. your functions can fail but they panic instead (you never actually return an Err); if you're going to try and create a file when opening it for writing fails, why not just do that directly[0]; you are manually calling write_fmt and format_args why not just write!; write_fmt already returns an io::Error why do you discard it then ask for it again via Error::last_os_error; etc...
It's also a bit strange to hand-roll your own logger thing when the rust ecosystem already has a bunch of them though you do you; and the naming is also somewhat awkward e.g. I'd expect something called set_X to actually set the X, so to me set_log would be a way to set the file being logged to.
[0] .create(true).append(true) should open the file in append mode if it exists and create it otherwise; not to mention your version has a concurrency issue: if the open-for-append fails you create the file in write mode, but someone else could have created the file -- with content -- between the two calls, in which case you're going to partially overwrite the file

Why do I get a Bad File Descriptor error when writing to opened File?

Calling write_all on a file returns an error with the description: os error. Debug printing the error outputs: Err(Error { repr: Os(9) })
What does the error mean?
You didn't include any code, so I had to make wild guesses about what you are doing. Here's one piece of code that reproduces your error:
use std::fs;
use std::io::Write;
fn main() {
let mut f = fs::File::open("/").unwrap();
// f.write_all(b"hello").unwrap();
// Error { repr: Os(9) }
match f.write_all(b"hello") {
Ok(..) => {},
Err(e) => println!("{}", e),
}
// Bad file descriptor (os error 9)
}
If you use the Display ({}) format instead of Debug ({:?}), you will see an error message that is nicer than just the error code. Note that unwrap will use the Debug formatter, so you have to use match in this case.
You could also look up the error code in the kernel source. You don't indicate if you are running Windows (unlikely), OS X or Linux, so I guessed Linux.
There are lots of SO questions that then explain what the code can mean, but I'm sure you know how to search through those, now that you have a handle on the problem.

Default Audio Output - Getting Device Changed Notification? (CoreAudio, Mac OS X, AudioHardwareAddPropertyListener)

I am trying to write a listener using the CoreAudio API for when the default audio output is changed (e.g.: a headphone jack is plugged in). I found sample code, although a bit old and using deprecated functions (http://developer.apple.com/mac/library/samplecode/AudioDeviceNotify/Introduction/Intro.html, but it didn't work. Re-wrote the code in the 'correct' way using AudioHardwareAddPropertyListener method, but still it doesn't seem to work. When I plug in a headphone the function that I registered is not triggered. I'm a bit of a loss here... I suspect the problem may lay some where else, but I can't figure out where...
The Listener Registration Code:
OSStatus err = noErr;
AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDefaultOutputDevice, KAudioObjectPropertyScopeGlobal, KAudioObjectPropertyElementMaster };
err = AudioObjectAddPropertyListener ( KAudioObjectAudioSystemObject, &AudioDevicesAddress, coreaudio_property_listener, NULL);
if (err) trace ("error on AudioObjectAddPropertyListener");
After a search in sourceforge for projects that used the CoreAudio API, I found the rtaudio project, and more importantly these lines:
// This is a largely undocumented but absolutely necessary
// requirement starting with OS-X 10.6. If not called, queries and
// updates to various audio device properties are not handled
// correctly.
CFRunLoopRef theRunLoop = NULL;
AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
if ( result != noErr ) {
errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";
error( RtError::WARNING );
}
After adding this code I didn't even need to register a listener myself.
Try CFRunLoopRun() - it has the same effect. i.e. making sure the event loop that is calling your listener is running.

Resources