I have a problem, which is the opposite to problem described here: cocoa-global-shortcuts. Example: when I assigning "a" key as shortcut (without modifiers) every time I press "a" my callback fired, but other applications don't get "a" press: TextEdit, XCode, etc. I don't want to "consume" the event.
Here is the code:
EventTypeSpec eventTypePressed = { kEventClassKeyboard, kEventHotKeyPressed };
InstallApplicationEventHandler(&HotKeyPressedHandler, 1, &eventTypePressed, self, NULL);
EventTypeSpec eventTypeReleased = { kEventClassKeyboard, kEventHotKeyReleased };
InstallApplicationEventHandler(&HotKeyReleasedHandler, 1, &eventTypeReleased, self, NULL);
EventHotKeyID eventHotKeyID = { 'htky', 1 };
RegisterEventHotKey(shortcut.code, shortcut.flags, eventHotKeyID, GetApplicationEventTarget(), 0, &_eventHotKeyRef);
OSStatus HotKeyPressedHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) {
ShortcutHandler* handler = userData;
[handler.delegate keyWasPressed:handler];
return CallNextEventHandler(nextHandler, theEvent);
}
OSStatus HotKeyReleasedHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) {
ShortcutHandler* handler = userData;
[handler.delegate keyWasReleased:handler];
return CallNextEventHandler(nextHandler, theEvent);
}
Thanks!
Related
I am trying to pass my custom buffer to WinRT objects that take IBuffer as argument. Here is what I have so far;
static const uint32_t ARRAY_SIZE = 4096;
struct ArrayBuffer : implements<ArrayBuffer, IBuffer, winrt::impl::IBufferByteAccess>
{
uint32_t Capacity() const { return ARRAY_SIZE; }
uint32_t Length() const { return length; }
void Length(uint32_t value)
{
if (value > ARRAY_SIZE)
throw hresult_invalid_argument();
length = value;
}
int32_t __stdcall Buffer(uint8_t** value)
{
*value = &data[0];
return 0;
}
private:
uint32_t length = 0;
uint8_t data[ARRAY_SIZE];
};
I am trying to use it like this;
fire_and_forget WebSocketServer::readLoop(StreamSocket socket)
{
IBuffer buffer = make<ArrayBuffer>();
auto istream = socket.InputStream();
while (true)
{
try
{
co_await istream.ReadAsync(buffer, ARRAY_SIZE, InputStreamOptions::None);
}
catch (hresult_error const& ex)
{
hresult hr = ex.code();
hstring message = ex.message();
}
if (buffer.Length() == 0)
break;
buffer.Length(0);
}
}
However, I am getting hresult_no_interface exception when I call ReadAsync method.
I am sending keyboard key press and key release events, which works for all keyboard keys.
But modifier keys works only when the key associated with modifier key is sent from application, and not from real hardware. That is if I send
Shift and 'a' from application, it prints 'A' (capital A, which is what is expected).
But if I send 'shift' key down event from application, and enter 'a' from physical keyboard, it prints 'a' (the shift key doesn't seem to be working across different devices). The same applies for other modifier keys such as cmd, alt, and fn keys!.
Is there a way to send modifier keys to system, so that I can emulate modifier keys from my application?.
Specifically, I would like to activate modifier key from application, and enter the combination key from physical keyboard.
Here is the code I use to send key press and release events.
- (void)setADBKey:(uint32)key value:(int)value
{
if (!eventSource)
{
eventSource = CGEventSourceCreate(kCGEventSourceStatePrivate);
}
CGEventRef event = CGEventCreateKeyboardEvent(eventSource, key, value!=0);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
I have also tried creating and sending a system event, through the following code
struct
{
CGKeyCode keyCode;
int flag;
int cgEventFlag;
} modifiers[] = {
{ 56, NX_DEVICELSHIFTKEYMASK, kCGEventFlagMaskShift },
{ 60, NX_DEVICERSHIFTKEYMASK, kCGEventFlagMaskShift },
{ 59, NX_DEVICELCTLKEYMASK, kCGEventFlagMaskControl },
{ 58, NX_DEVICELALTKEYMASK, kCGEventFlagMaskAlternate },
{ 61, NX_DEVICERALTKEYMASK, kCGEventFlagMaskAlternate },
{ 55, NX_DEVICELCMDKEYMASK, kCGEventFlagMaskCommand },
{ 54, NX_DEVICERCMDKEYMASK, kCGEventFlagMaskCommand }
};
- (void)setAdbKey:(uint32)adbkey value:(int)value repeat:(BOOL)repeat
{
//int adbkey = def_usb_2_adb_keymap[hidkey];
int modifier = 0;
for(int i=0; i< ARR_SIZE(modifiers); i++)
{
if (adbkey == modifiers[i].keyCode)
{
modifier = modifiers[i].cgEventFlag;
break;
}
}
if (value)
{
flags |= modifier;
}
else
{
flags &= ~modifier;
}
CGEventRef event = CGEventCreateKeyboardEvent(eventSource, adbkey, value!=0);
if (repeat)
{
CGEventSetIntegerValueField(event, kCGKeyboardEventAutorepeat, (int64_t)1);
}
// don't apply modifier flags to a modifier
if (!modifier)
{
CGEventSetFlags(event, flags);
}
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
Both methods work when modifier key and combination key are sent from application, but not when modifier key alone is set from application.
All you have to do is create an event tap and set the mask.
Sample:
#interface AppDelegate ()
#property (assign) CFMachPortRef myEventTap;
#property (assign) CFRunLoopSourceRef myRunLoopSource;
#end
#implementation AppDelegate
CGEventRef MyEventTapCallBack(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGEventSetFlags(event, kCGEventFlagMaskShift);
return event;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.myEventTap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged),
MyEventTapCallBack,
(__bridge void *)self);
if (self.myEventTap) {
self.myRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.myEventTap, 0);
if (self.myRunLoopSource)
CFRunLoopAddSource(CFRunLoopGetMain(), self.myRunLoopSource, kCFRunLoopCommonModes);
}
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
if (self.myRunLoopSource) {
CFRunLoopSourceInvalidate(self.myRunLoopSource);
CFRelease(self.myRunLoopSource);
}
if (self.myEventTap)
CFRelease(self.myEventTap);
}
#end
This is my appDelegate and how I got it working.
import Cocoa
import CoreGraphics
import Foundation
var shift = false;
var cntrl = false;
var option = false;
var command = false;
func myCGEventCallback(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent, refcon: UnsafeMutableRawPointer?) -> Unmanaged<CGEvent>? {
var mask: CGEventFlags = []
if(shift) {
mask.insert(CGEventFlags.maskShift)
}
if(cntrl) {
mask.insert(CGEventFlags.maskControl)
}
if(option) {
mask.insert(CGEventFlags.maskAlternate)
}
if(command) {
mask.insert(CGEventFlags.maskCommand)
}
if(mask.rawValue != 0) {
event.flags = mask;
}
return Unmanaged.passRetained(event)
}
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let mask: CGEventMask = 1 << CGEventType.keyDown.rawValue
let eventTap:CFMachPort = CGEvent.tapCreate(tap: .cghidEventTap, place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: mask, callback: myCGEventCallback, userInfo: nil)!
let runLoopSource:CFRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, CFRunLoopMode.commonModes);
CGEvent.tapEnable(tap: eventTap, enable: true);
CFRunLoopRun();
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
public func SetShift() {
shift = !shift;
}
public func SetCtrl() {
cntrl = !cntrl;
}
public func SetCommand() {
command = !command;
}
public func SetOption() {
option = !option;
}
}
I'm working with a treeview, which contains several columns, also one displaying a pixbuf, if audio is playing or paused. If the user double clicks on one row, audio playback starts and the row needs to be rerendered in order to display the pixbuf icon. I used QueueDraw for this, but that does only work, if the cursor leaves the current row. How can I update the pixbuf directly?
CODE:
protected void trvMainCuesheetRowActivated (object o, RowActivatedArgs args)
{
log.debug("trvMainCuesheetRowActivated called");
TreeIter ti = TreeIter.Zero;
this.lsCuesheetData.GetIter(out ti,args.Path);
if (this.lsCuesheetData.GetValue(ti,0) != null)
{
Track tCurTrack = (Track)this.lsCuesheetData.GetValue(ti,0);
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Stopped)
{
this.objProgram.getAudioManager().play(tCurTrack);
this.refresh();
}
else
{
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Playing)
{
this.objProgram.getAudioManager().seek(tCurTrack);
this.refresh();
}
}
}
}
private void renderPlaying(TreeViewColumn _tvcColumn, CellRenderer _crCell, TreeModel _tmModel, TreeIter _tiIter)
{
Track tCurTrack = (Track)_tmModel.GetValue (_tiIter, 0);
//Just display an icon, if we are playing
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Playing)
{
if (this.objProgram.getAudioManager().getCurrentlyPlayingTrack() == tCurTrack)
{
Gdk.Pixbuf icon = this.RenderIcon(Stock.MediaPlay, IconSize.SmallToolbar, null);
(_crCell as CellRendererPixbuf).Pixbuf = icon;
}
else
{
(_crCell as CellRendererPixbuf).Pixbuf = null;
}
}
else
{
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Paused)
{
if (this.objProgram.getAudioManager().getCurrentlyPlayingTrack() == tCurTrack)
{
Gdk.Pixbuf icon = this.RenderIcon(Stock.MediaPause, IconSize.SmallToolbar, null);
(_crCell as CellRendererPixbuf).Pixbuf = icon;
}
else
{
(_crCell as CellRendererPixbuf).Pixbuf = null;
}
}
else
{
(_crCell as CellRendererPixbuf).Pixbuf = null;
}
}
}
//Purpose: Function used to refresh the MainWindow depending on new options set.
public void refresh()
{
//QueueDraw is needed since it fires a signal to cellrenderers to update
this.trvMainCuesheet.QueueDraw();
this.sbMainWindow.Visible = this.objProgram.getObjOption().getBShowStatusbar();
this.mwToolbar.Visible = this.objProgram.getObjOption().getBToolbarVisible();
}
Greetings
Sven
Found the error myself.
this.objProgram.getAudioManager().getCurrentlyPlayingTrack()
didn't always return a track, where I expected one, so the renderer worked right. Bug is fixed, thanks anyway ;).
I want to send messages periodically through this program, the messages are broadcasted fine and I get a sendDone message. The problem is that these messages are not received well. I would really appreciate any help to find out where the problem is?
Here is the code(please ignore unused variables as I have cut a lot of the code):
includes lqer;
module lqer_M{
provides {
interface SplitControl;
interface AMSend[am_id_t id];
interface Receive[uint8_t id];
};
uses {
interface SplitControl as AMControl;
interface Timer<TMilli> as LQERTimer;
interface Random;
interface AMPacket;
interface AMSend as SendPacket;
interface Receive as ReceivePacket;
interface PacketAcknowledgements;
interface Packet;
}
}
implementation{
message_t lqer_msg_;
message_t* p_lqer_msg_;
lqer_table l_table[LQER_FT_SIZE];
node_info info;
uint8_t max=0, Pos=0;
message_t* newADV;
bool busy = FALSE;
command error_t SplitControl.start() {
int i,j;
p_lqer_msg_ = &lqer_msg_;
info.hop=1000;
for(i=0; i<16; i++){
info.m[i]=1;
}
for(i = 0; i< LQER_FT_SIZE; i++) {
l_table[i].nid = INVALID_NODE_ID;
l_table[i].hop = 1000;
for (j=0; j<16; j++)
{
l_table[i].m[j]=1;
}
}
call AMControl.start();
return SUCCESS;
}
command error_t SplitControl.stop() {
call AMControl.stop();
return SUCCESS;
}
event void AMControl.startDone( error_t e ) {
if ( e == SUCCESS ) {
call LQERTimer.startPeriodic( LQER_DEFAULT_PERIOD );
signal SplitControl.startDone(e);
} else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t e){
call LQERTimer.stop();
signal SplitControl.stopDone(e);
}
event void LQERTimer.fired() {
message_t* lqer_adv_msg;
lqer_adv_hdr* new_ADV=(lqer_adv_hdr*)(lqer_adv_msg->data);
am_addr_t me = call AMPacket.address();
if (me==0001){
new_ADV->src = me;
new_ADV->hop = 0;
newADV= (message_t*)(&new_ADV);
dbg("GRAPE_DBG", "%s\t LQER: Sink address: %d\n", sim_time_string(), me);
call PacketAcknowledgements.requestAck(newADV);
call SendPacket.send( AM_BROADCAST_ADDR, newADV, call Packet.payloadLength(newADV) );
}
}
event message_t* ReceivePacket.receive( message_t* p_msg, void* payload, uint8_t len ) {
lqer_adv_hdr* lqer_hdr = (lqer_adv_hdr*)(p_msg->data);
lqer_adv_hdr* msg_lqer_hdr =(lqer_adv_hdr*)(p_lqer_msg_->data);
uint8_t i;
lqer_adv_hdr* new_ADV =(lqer_adv_hdr*)(p_lqer_msg_->data);
dbg("GRAPE_DBG", "%s\t ADV: RecievedADV dst: \n", sim_time_string());
msg_lqer_hdr->src = lqer_hdr->src;
msg_lqer_hdr->hop = lqer_hdr->hop;
new_ADV->src = msg_lqer_hdr->src;
new_ADV->hop = msg_lqer_hdr->hop;
newADV= (message_t*)(&new_ADV);
call PacketAcknowledgements.requestAck( newADV );
call SendPacket.send( AM_BROADCAST_ADDR, newADV, call Packet.payloadLength(newADV) );
return p_msg;
}
command error_t AMSend.cancel[am_id_t id](message_t* msg) {
return call SendPacket.cancel(msg);
}
command uint8_t AMSend.maxPayloadLength[am_id_t id]() {
return call Packet.maxPayloadLength();
}
command void* AMSend.getPayload[am_id_t id](message_t* m, uint8_t len) {
return call Packet.getPayload(m, 0);
}
default event void AMSend.sendDone[uint8_t id](message_t* msg, error_t err) {
return;
}
default event message_t* Receive.receive[am_id_t id](message_t* msg, void* payload, uint8_t len) {
return msg;
}
command error_t AMSend.send[am_id_t id](am_addr_t addr, message_t* msg, uint8_t len)
{
call SendPacket.send( TOS_BCAST_ADDR , msg, call Packet.payloadLength(msg) );
return SUCCESS;
}
event void SendPacket.sendDone(message_t* p_msg, error_t e) {
dbg("GRAPE_DBG", "%s\t ADV: SendDone\n", sim_time_string());
if( p_msg== newADV)
busy=FALSE;
}
}
You should look at what is the error value in the sendDone event. It is possible that send returns success, but the sending fail after that, and the error code is returned in the sendDone. These error includes ENOACK, ENOMEM, etc.
Also, check your destination address and the AM address of the receiver.
Is it possible for xcode to have an audio level indicator?
I want to do something like this:
if (audioLevel = 100) {
}
or something similar...
Any ideas?? Example code please?
I'm VERY new to objective c so the more explaining the beter! :D
Unfortunately, there isn't a very straightforward API to do this. You need to use the low level AudioToolbox.framework.
Luckily, others have already solved this problem for you. Here's some code I simplified slightly to be straight C functions, from CocoaDev. You need to link to the AudioToolbox to compile this code (see here for documentation on how to do so).
#import <AudioToolbox/AudioServices.h>
AudioDeviceID getDefaultOutputDeviceID()
{
AudioDeviceID outputDeviceID = kAudioObjectUnknown;
// get output device device
OSStatus status = noErr;
AudioObjectPropertyAddress propertyAOPA;
propertyAOPA.mScope = kAudioObjectPropertyScopeGlobal;
propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
propertyAOPA.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
if (!AudioHardwareServiceHasProperty(kAudioObjectSystemObject, &propertyAOPA))
{
printf("Cannot find default output device!");
return outputDeviceID;
}
status = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &propertyAOPA, 0, NULL, (UInt32[]){sizeof(AudioDeviceID)}, &outputDeviceID);
if (status != 0)
{
printf("Cannot find default output device!");
}
return outputDeviceID;
}
float getVolume ()
{
Float32 outputVolume;
OSStatus status = noErr;
AudioObjectPropertyAddress propertyAOPA;
propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
propertyAOPA.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMasterVolume;
propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
AudioDeviceID outputDeviceID = getDefaultOutputDeviceID();
if (outputDeviceID == kAudioObjectUnknown)
{
printf("Unknown device");
return 0.0;
}
if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA))
{
printf("No volume returned for device 0x%0x", outputDeviceID);
return 0.0;
}
status = AudioHardwareServiceGetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, (UInt32[]){sizeof(Float32)}, &outputVolume);
if (status)
{
printf("No volume returned for device 0x%0x", outputDeviceID);
return 0.0;
}
if (outputVolume < 0.0 || outputVolume > 1.0) return 0.0;
return outputVolume;
}
int main (int argc, char const *argv[])
{
printf("%f", getVolume());
return 0;
}
Note that there's also a setVolume function there, too.