I find MPMoviePlayerController.h,there is
enum {
MPMovieLoadStateUnknown = 0,
MPMovieLoadStatePlayable = 1 << 0,
MPMovieLoadStatePlaythroughOK = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES
MPMovieLoadStateStalled = 1 << 2, // Playback will be automatically paused in this state, if started
};
typedef NSInteger MPMovieLoadState;
but when i did
NSLog(#"%d",player.loadState)
it prints out 5 or sometimes 3,how did it happen?As i know the loadstate has value of 0,1,2,4 refer to developer documentation.
Thank you!
The playState is a bitmask. Any number of bits can be set, such as
MPMovieLoadStatePlaythroughOK | MPMovieLoadStatePlayable
Check for states like this:
MPMovieLoadState state = [playerController loadState];
if( state & MPMovieLoadStatePlaythroughOK ) {
NSLog(#"State is Playthrough OK");
}
Related
I have some code I've been using to get the current keyboard layout and convert a virtual key code into a string. This works great in most situations, but I'm having trouble with some specific cases. The one that brought this to light is the accent key next to the backspace key on german QWERTZ keyboards. http://en.wikipedia.org/wiki/File:KB_Germany.svg
That key generates the VK code I'd expect kVK_ANSI_Equal but when using a QWERTZ keyboard layout I get no description back. Its ending up as a dead key because its supposed to be composed with another key. Is there any way to catch these cases and do the proper conversion?
My current code is below.
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if(keyboardLayout)
{
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 255;
UniCharCount actualStringLength = 0;
UniChar unicodeString[maxStringLength];
OSStatus status = UCKeyTranslate(keyboardLayout,
keyCode, kUCKeyActionDown, 0,
LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
if(actualStringLength > 0 && status == noErr)
return [[NSString stringWithCharacters:unicodeString length:(NSInteger)actualStringLength] uppercaseString];
}
That key is a dead key, as you can see if you try it yourself or look at the Keyboard Viewer with the German layout active.
On the Mac, the way to enter a dead key's actual character, without composing it with another character, is to press a space after it. So try that: Turn off kUCKeyTranslateNoDeadKeysBit, and if UCKeyTranslate sets the dead-key state, translate a space after it.
EDIT (added by asker)
Just for future people, here is the fixed code with the right solution.
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if(keyboardLayout)
{
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 255;
UniCharCount actualStringLength = 0;
UniChar unicodeString[maxStringLength];
OSStatus status = UCKeyTranslate(keyboardLayout,
keyCode, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
if (actualStringLength == 0 && deadKeyState)
{
status = UCKeyTranslate(keyboardLayout,
kVK_Space, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
}
if(actualStringLength > 0 && status == noErr)
return [[NSString stringWithCharacters:unicodeString length:(NSUInteger)actualStringLength] uppercaseString];
}
I have seen many post on this topic. But haven't found a clear answer anywhere.
Is there a way to toggle CAPS LOCK in Objective-C or C code? I am not looking for a solution using X11 libs. I am not bothered about the LED on/off status. But just the functionality of CAPS LOCK (changing the case of letters and printing the special characters on number keys).
Why is CGEvent not supporting this the way it does for other keys?
var ioConnect: io_connect_t = .init(0)
let ioService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass))
IOServiceOpen(ioService, mach_task_self_, UInt32(kIOHIDParamConnectType), &ioConnect)
var modifierLockState = false
IOHIDGetModifierLockState(ioConnect, Int32(kIOHIDCapsLockState), &modifierLockState)
modifierLockState.toggle()
IOHIDSetModifierLockState(ioConnect, Int32(kIOHIDCapsLockState), modifierLockState)
IOServiceClose(ioConnect)
The following method also works when you want CapsLock to toggle the current keyboard language (if you have the CapsLock key configured to do that).
CFMutableDictionaryRef mdict = IOServiceMatching(kIOHIDSystemClass);
io_service_t ios = IOServiceGetMatchingService(kIOMasterPortDefault, (CFDictionaryRef)mdict);
if (ios) {
io_connect_t ioc = 0;
IOServiceOpen(ios, mach_task_self(), kIOHIDParamConnectType, &ioc);
if (ioc) {
NXEventData event{};
IOGPoint loc{};
// press CapsLock key
UInt32 evtInfo = NX_KEYTYPE_CAPS_LOCK << 16 | NX_KEYDOWN << 8;
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
event.compound.misc.L[0] = evtInfo;
IOHIDPostEvent(ioc, NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
// release CapsLock key
evtInfo = NX_KEYTYPE_CAPS_LOCK << 16 | NX_KEYUP << 8;
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
event.compound.misc.L[0] = evtInfo;
IOHIDPostEvent(ioc, NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
IOServiceClose(ioc);
}
}
I got this working, after a long struggle.
Invoke the method given below twice. Once for up event and another for down event. For example for simulating CAPS A, we need to do the following.
[self handleKeyEventWithCapsOn:0 andKeyDown:NO];
[self handleKeyEventWithCapsOn:0 andKeyDown:YES];
0 is the keycode for 'a'.
- (void) handleKeyEventWithCapsOn:(int) keyCode andKeyDown:(BOOL)keyDown
{
if(keyDown)
{
CGEventRef eventDown;
eventDown = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)keyCode, true);
CGEventSetFlags(eventDown, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, eventDown);
CFRelease(eventDown);
}
else
{
CGEventRef eventUp;
eventUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)keyCode, false);
CGEventSetFlags(eventUp, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, eventUp);
// SHIFT Up Event
CGEventRef eShiftUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, eShiftUp);
CFRelease(eventUp);
CFRelease(eShiftUp);
}
}
I'm writing an app in swift that lives in the menu bar at the top of the screen. I need both a global and local event monitor to open the popover on a specific key press. There is no problem with the local event monitor, but when the user hits the key command (cmd+shift+8) from inside an app like Finder, the popover opens but the mac error "Funk" sound is played as well. Is there any way I can disable this? Perhaps some way for the app to eat the sound, or register it as a valid keyboard shortcut so the sound is never played?
Here is the code:
NSEvent.addGlobalMonitorForEvents(matching: NSEventMask.keyDown, handler: {(event: NSEvent!) -> Void in
if (event.keyCode == 28 && event.modifierFlags.contains(NSEventModifierFlags.command) && event.modifierFlags.contains(NSEventModifierFlags.shift)){
self.togglePopover(sender: self)
}
});
NSEvent.addLocalMonitorForEvents(matching: NSEventMask.keyDown, handler: {(event: NSEvent!) -> NSEvent? in
if (event.keyCode == 28 && event.modifierFlags.contains(NSEventModifierFlags.command) && event.modifierFlags.contains(NSEventModifierFlags.shift)){
self.togglePopover(sender: self)
}
return event
});
I ended up using MASShortcut as a workaround solution to this issue.
In your addGlobalMonitorForEventsMatchingMask handler, save the current volume level and turn the volume down on both channels. You can do you own event processing in the handler before or after turning down the volume.
Before returning from the handler, restore the original volume, but include a delay to give the OS time to process the event (it will send the "funk," but you won't hear it).
One side effect: if you're listening to something (e.g., music), that will be briefly silenced, too.
My event code:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown
handler:^(NSEvent *event) {
if ( event.type == NSEventTypeKeyDown ) {
if ( event.keyCode == 106 ) { // F16
// process the event here
[self adjustVolume:#(NO)];
[self performSelector:#selector(adjustVolume:) withObject:#(YES) afterDelay:0.3];
// 0.2 seconds was too soon
}
}
}];
My volume adjustment code:
- (void)adjustVolume:(NSNumber *)offOn
{
// get audio device...
AudioObjectPropertyAddress getDefaultOutputDevicePropertyAddress = {
kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
AudioDeviceID defaultOutputDeviceID;
UInt32 infoSize = sizeof(defaultOutputDeviceID);
AudioObjectGetPropertyData(kAudioObjectSystemObject,
&getDefaultOutputDevicePropertyAddress,
0, NULL,
&infoSize, &defaultOutputDeviceID);
// structurs to access the left/right volume setting
AudioObjectPropertyAddress volumePropertyAddress1 = {
kAudioDevicePropertyVolumeScalar,
kAudioDevicePropertyScopeOutput,
1 /* left */
};
AudioObjectPropertyAddress volumePropertyAddress2 = {
kAudioDevicePropertyVolumeScalar,
kAudioDevicePropertyScopeOutput,
2 /* right */
};
// save the original volume (assumes left/right are the same
static Float32 volumeOriginal; // could be an iVar
if ( offOn.boolValue == NO ) { // turn off
UInt32 volumedataSize = sizeof(volumeOriginal);
AudioObjectGetPropertyData(defaultOutputDeviceID,
&volumePropertyAddress1,
0, NULL,
&volumedataSize, &volumeOriginal);
//NSLog(#"volumeOriginal %f",volumeOriginal);
// turn off both channels
Float32 volume = 0.0;
AudioObjectSetPropertyData(defaultOutputDeviceID,
&volumePropertyAddress1,
0, NULL,
sizeof(volume), &volume);
AudioObjectSetPropertyData(defaultOutputDeviceID,
&volumePropertyAddress2,
0, NULL,
sizeof(volume), &volume);
} else { // restore
//NSLog(#"restoring volume");
AudioObjectSetPropertyData(defaultOutputDeviceID,
&volumePropertyAddress1,
0, NULL,
sizeof(volumeOriginal), &volumeOriginal);
AudioObjectSetPropertyData(defaultOutputDeviceID,
&volumePropertyAddress2,
0, NULL,
sizeof(volumeOriginal), &volumeOriginal);
}
}
With recognition to Thomas O'Dell for getting me started on this Change OS X system volume programmatically
Hello I am using a library. It has some options embedded in enum, but i can't figure out how to configure them. The library is called PPRevealSideViewController.
It has a property:
#property (nonatomic, assign) PPRevealSideOptions options;
Here is the enum code:
enum {
PPRevealSideOptionsNone = 0,
PPRevealSideOptionsShowShadows = 2 << 1, /// Disable or enable the shadows. Enabled by default
PPRevealSideOptionsBounceAnimations = 1 << 2, /// Decide if the animations are boucing or not. By default, they are
PPRevealSideOptionsCloseCompletlyBeforeOpeningNewDirection = 1 << 3, /// Decide if we close completely the old direction, for the new one or not. Set to YES by default
PPRevealSideOptionsKeepOffsetOnRotation = 1 << 4, /// Keep the same offset when rotating. By default, set to no
PPRevealSideOptionsResizeSideView = 1 << 5, /// Resize the side view. If set to yes, this disabled the bouncing stuff since the view behind is not large enough to show bouncing correctly. Set to NO by default
};
typedef NSUInteger PPRevealSideOptions;
Thank you very much!
obj.options = opt0 | opt1 | ... etc
For example: obj.options = PPRevealSideOptionsBounceAnimations | PPRevealSideOptionsResizeSideView;
I made a documentation of this controller for that purpose. Well, my bad, this method is not very highlighted, but does exist :
You can reset an option using - (void) resetOption:(PPRevealSideOptions)option; (behind, it is low level : _options ^= option;)
Or set an option by using - (void) setOption:(PPRevealSideOptions)option. There is even a setOptionS method ;)
I am using the Audio Queue services to record audio on the iPhone. I am having a latency issue though when starting recording. Here is the code (approx):
OSStatus status = AudioQueueNewInput(
&recordState.dataFormat, // 1
AudioInputCallback, // 2
&recordState, // 3
CFRunLoopGetCurrent(), // 4
kCFRunLoopCommonModes, // 5
0, // 6
&recordState.queue); // 7
// create buffers
for(int i = 0; i < NUM_BUFFERS; i++)
{
if (status == 0)
status = AudioQueueAllocateBuffer(recordState.queue, BUFFER_SIZE, &recordState.buffers[i]);
}
DebugLog(#"Starting recording\n");
OSStatus status = 0;
for(int i = 0; i < NUM_BUFFERS; i++)
{
if (status == 0)
status = AudioQueueEnqueueBuffer(recordState.queue, recordState.buffers[i], 0, NULL);
}
DebugLog(#"Queued buffers\n");
if (status == 0)
{
// start audio queue
status = AudioQueueStart(recordState.queue, NULL);
}
DebugLog(#"Started recording, status = %d\n", status);
The log output looks like this:
2009-06-30 19:18:59.631 app[24887:20b] Starting recording
2009-06-30 19:18:59.828 app[24887:20b] Queued buffers
2009-06-30 19:19:00.849 app[24887:20b] Started recording, status = 0
Note the 1-second delay between the "Queued Buffers" message and 2nd "Starting recording" message. Any ideas how I can get rid of it, apart from starting recording as soon as I start my app?
BTW, the 1-second is pretty consistent in the Simulator and Device, and doesn't seem to be affected by number or size of buffers. Using good old mono 16-bit PCM.
Mike Tyson covers this in his blog.
However, if you're looking to quickly start recording you would do better to use a remote audio unit, or AVAudioEngine.