GLFW key input on GNOME 3 desktop - x11

I've a problem with GLFW3 on a GNOME 3 desktop.
I've tested this on several Linux machines, including a fresh installed Ubuntu 16.04 LTS machine (with Unity).
The problem occurs in every GLFW3 application.
If i press and hold any key, a normal key GLFW_PRESS, and while holding the GLFW_REPEAT events are emitted.
But if I release the key, one GLFW_RELEASE event is emitted, following by another GLFW_PRESS (and sometimes multiple GLFW_REPEAT) events.
Here a minimal example:
#include <GLFW/glfw3.h>
#include <cstdio>
void glfw_key_callback(GLFWwindow* w, int key, int scancode, int action, int mods) {
printf("win %p: key %d, scancode %d, action %d, mods %d\n", w, key, scancode, action, mods);
}
int main() {
if (!glfwInit()) {
printf("Failed to init glfw!\n");
return 1;
}
GLFWwindow* window = glfwCreateWindow(800, 600, "Key input test", 0, 0);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, glfw_key_callback);
while (!glfwWindowShouldClose(window)) {
glfwWaitEvents();
glfwSwapBuffers(window);
}
return 0;
}
Example output when I press and hold Space and release it after a few seconds:
win 0x104fb20: key 32, scancode 65, action 1, mods 0
win 0x104fb20: key 32, scancode 65, action 2, mods 0
...
win 0x104fb20: key 32, scancode 65, action 2, mods 0
win 0x104fb20: key 32, scancode 65, action 0, mods 0
win 0x104fb20: key 32, scancode 65, action 1, mods 0
win 0x104fb20: key 32, scancode 65, action 2, mods 0
win 0x104fb20: key 32, scancode 65, action 0, mods 0
I also have tried to compile and run this program with the current GLFW3 dev version (from https://github.com/glfw/glfw.git ) but with the same result.
Then i searched in the glfw3 source code where this events came from.
I found the XPending() call in the glfw3 source x11_window.c.
But it looks as that this additions events are emitted from the X11 system,
so I am not sure if this is a GLFW or X11 problem?
On other desktop environments such as Mate Desktop everything works fine for me.

Related

Autoit - limiting the number of execution

I don't know if it's possible cuz i couldn't find anywhere.
I have created a GUI with some buttons to start things.
I'm just wondering if it is possible to:
limit the number of openings of the GUI
limit the number of executions with the buttons
limit the time range so that after certain point, u can't use it
Global $explain = "help~~"
#include <IE.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Global $explain = "hmmm"
Global $Form1 = GUICreate("Yay", 328, 157)
Global $Label1 = GUICtrlCreateLabel("ID", 12, 14, 67, 20)
Global $Label2 = GUICtrlCreateLabel("Password", 12, 44, 67, 20)
Global $Label3 = GUICtrlCreateLabel("hello world", 225, 14, 90, 20)
Global $Input1 = GUICtrlCreateInput("", 76, 10, 105, 24)
Global $Input2 = GUICtrlCreateInput("", 76, 40, 105, 24, BitOR($ES_PASSWORD, $ES_AUTOHSCROLL))
Global $Input3 = GUICtrlCreateInput("", 228, 40, 70, 24)
Global $Button1 = GUICtrlCreateButton("Log In", 76, 69, 105, 30)
Global $Button2 = GUICtrlCreateButton("Connect", 212, 69, 100, 30)
Global $Checkbox1 = GUICtrlCreateCheckbox("hmm", 240, 113, 97, 17)
Global $Checkbox2 = GUICtrlCreateCheckbox("hmm2", 240, 134, 97, 17)
Global $Group1 = GUICtrlCreateGroup("", 5, -5, 190, 110)
Global $Edit1 = GUICtrlCreateEdit("", 5, 110, 228, 100)
GUICtrlSetData(-1, $explain)
GUISetState(#SW_SHOW)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Checkbox1
If (GUICtrlRead($Checkbox1) = $GUI_CHECKED) Then
Global $hmm = 1
EndIf
Case $Checkbox2
If (GUICtrlRead($Checkbox2) = $GUI_CHECKED) Then
Global $hmm2 = 0
EndIf
Case $Button1
Global $id = GUICtrlRead($Input1)
Global $pass = GUICtrlRead($Input2)
WinSetState("Yay", "", #SW_MINIMIZE)
MsgBox(0,"","possible to limit #of Execution?")
Case $Button2
Global $exnum = GUICtrlRead($Input3)
WinSetState("Yay", "", #SW_MINIMIZE)
MsgBox(0,"","time limit would be nice too! thnx!")
EndSwitch
WEnd
Has anyone tried this?
Will it require intense coding?
Could you provide a sample if it isn't too bad
Good afternoon Pita,
Yup! It's all definitely possible to do! There's multiple ways to do so, I'll try to name a few.
A good way for you to manage these requests, would be to make a properties file to manage everything. Take a look at my example below!
Global $explain = "help~~"
#include <IE.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
; =================================================================================================================================================
#include <File.au3>
#Include <Date.au3>
; This is the directory that the temporary file will be stored.
$fileHandle = #AppDataDir & "\TestProgram\properties.txt"
; Checks to see if the properties file exists
if FileExists($fileHandle) Then
; START Check Run Limit
; Reads the first value in the properties file. In this example, it's the limit to how many times the program can be launched.
$runLimit = FileReadLine($fileHandle, 1)
; MsgBox(0,"Run Limit", $runLimit)
; If the run limit reaches zero (or less than by some glitch), do not launch the program.
if $runLimit <= 0 Then
MsgBox(16,"Run Limit Reached", "You have reached the maximum number of launches for this program!")
Exit
EndIf
; Subtract one from the launch limit.
$newLimit = $runLimit - 1
MsgBox(0,"New Run Limit", "You may launch this program " & $newLimit & " more times!", 3)
; Update the properties file.
_FileWriteToLine($fileHandle, 1, $newLimit, True)
; END Check Run Limit
; Start CHECK Expiration Date
$expDate = FileReadLine($fileHandle, 2)
; MsgBox(0,"Expiration Date", "This program expires on " & $expDate)
; Check to see if the expiration date has already passed
if $expDate < _NowDate() Then
MsgBox(16,"Program Expired","Your trial period has expired!")
Exit
EndIf
; END Check expiration date
Else
; If the file does not exists, create it and set it up
$propFile = FileOpen($fileHandle, 10)
; Sets the launch limit to 10. Change this value to set the launch limit
FileWrite($fileHandle, "10" & #CRLF)
; Sets the expiration date to a week (7 days) from the initial launch date.
FileWrite($fileHandle, #MON & "/" & (#MDAY + 7) & "/" & #YEAR & #CRLF)
; Sets the button limit for the login button to 3.
FileWrite($fileHandle, "3" & #CRLF)
FileClose($fileHandle)
#CS
NOTE: THIS IS JUST FOR DEMONSTRATION PURPOSES! THE USER CAN SIMPLY DELETE THE PROPERTIES FILE
IN ORDER TO RESET THE VALUES AND CONTINUE USING THE PROGRAM. THIS WAS DESIGNED SIMPLY TO
GET YOU ON THE RIGHT TRACK.
#CE
EndIf
; =================================================================================================================================================
Global $explain = "hmmm"
Global $Form1 = GUICreate("Yay", 328, 157)
Global $Label1 = GUICtrlCreateLabel("ID", 12, 14, 67, 20)
Global $Label2 = GUICtrlCreateLabel("Password", 12, 44, 67, 20)
Global $Label3 = GUICtrlCreateLabel("hello world", 225, 14, 90, 20)
Global $Input1 = GUICtrlCreateInput("", 76, 10, 105, 24)
Global $Input2 = GUICtrlCreateInput("", 76, 40, 105, 24, BitOR($ES_PASSWORD, $ES_AUTOHSCROLL))
Global $Input3 = GUICtrlCreateInput("", 228, 40, 70, 24)
Global $Button1 = GUICtrlCreateButton("Log In", 76, 69, 105, 30)
Global $Button2 = GUICtrlCreateButton("Connect", 212, 69, 100, 30)
Global $Checkbox1 = GUICtrlCreateCheckbox("hmm", 240, 113, 97, 17)
Global $Checkbox2 = GUICtrlCreateCheckbox("hmm2", 240, 134, 97, 17)
Global $Group1 = GUICtrlCreateGroup("", 5, -5, 190, 110)
Global $Edit1 = GUICtrlCreateEdit("", 5, 110, 228, 100)
GUICtrlSetData(-1, $explain)
GUISetState(#SW_SHOW)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Checkbox1
If (GUICtrlRead($Checkbox1) = $GUI_CHECKED) Then
Global $hmm = 1
EndIf
Case $Checkbox2
If (GUICtrlRead($Checkbox2) = $GUI_CHECKED) Then
Global $hmm2 = 0
EndIf
Case $Button1
; START Button Limit ================================================================================================================
if FileExists($fileHandle) Then
$buttonLimit = FileReadLine($fileHandle, 3)
if $buttonLimit <= 0 Then
MsgBox(16,"Button Limit Reached", "You have reached the maximum number of times you can hit this button!")
ELSE
$newButtonLimit = $buttonLimit - 1
MsgBox(0,"New Run Limit", "You may press this button " & $newButtonLimit & " more times!", 3)
_FileWriteToLine($fileHandle, 3, $newButtonLimit, True)
; START OLD CODE
Global $id = GUICtrlRead($Input1)
Global $pass = GUICtrlRead($Input2)
; WinSetState("Yay", "", #SW_MINIMIZE)
MsgBox(0,"","possible to limit #of Execution?")
; END OLD CODE ================================================================================================================
EndIf
EndIf
; END Button Limit
Case $Button2
Global $exnum = GUICtrlRead($Input3)
WinSetState("Yay", "", #SW_MINIMIZE)
MsgBox(0,"","time limit would be nice too! thnx!")
EndSwitch
WEnd
Upon launching the program, a property file is generated and stored in the appdata on the users computer.
On windows: Press Win+R and type %appdata%. If you left the example the same, there will be a folder called "TestProgram", if you changed the name, it will be whatever you called it. Inside of this folder, there will be the properties.txt file (Again, unless you changed the name).
I have made some comments in the example code to help explain what I did, but I'm not fantastic at explaining things so please let me know if you need some more help.
P.S. If you do use this method, I strongly suggest encrypting (Using Crypt maybe?) the properties file to make it a little less editable and designing some way to tell if the user deleted the file.
I hope this helps!,
Tim

A dialog box in winapi

I've got a slight problem with my dialog box. it shows its contents in the parent windows. instead of a different frame, nothing seems to be wrong. I used the DS_MODALFRAME and the WS_ styles but it isn't working
END
This is the dialog procedure
BOOL CALLBACK AboutDialog(HWND fsr_win,UINT f_msg, WPARAM fwParam, LPARAM flParam)
{
switch (f_msg)
{
case WM_COMMAND:
switch(fwParam)
{
case ID_OK:
EndDialog(fsr_win,TRUE);
return TRUE;
break;
};
return TRUE;
};
return TRUE;
}
1 RT_MANIFEST "File searcher 2.exe.Manifest"
FSR_ABOUT DIALOG FIXED 6, 21, 100,100
STYLE DS_MODALFRAME
CAPTION "About Generic"
FONT 10, "MS Shell Dlg"
BEGIN
DEFPUSHBUTTON "&Okay", ID_OK, 40, 80, 40, 10
LTEXT "File searcher", 104, 10, 20,90,
8
LTEXT "Copyright © DONSN® 2014 ", 107, 10,40,90, 8
END
B
The simple solution was to change a bit of the line of code in the dialog procedure which apparently returns true instead of false...
So we have
{
/* after the case statements*/
Return FALSE
}
And that's all it shows with a close button...but with the common control stuff on.

Undefined reference during linking with DUMB and Allegro

Ive been up for 10 hours trying to figure out this. Ive tried out a bunch of different libraries to try to get ogg or mp3 files to play with allegro 4. I downloaded DUMB library and copied the include and lib files to mingw respective places (i use codeblocks).
What is the correct way to install a library to my compiler?
here is my code so far..
#include <allegro.h>
#include <iostream>
#include <stdlib.h>
#include <aldumb.h>
#include "CUSTOM_FUNCTIONS_HEADER.h"
#include "status_screen_functions_header.h"
#define WHITE makecol(255,255,255)
//General Game Settings
int volume = 128;
int pan = 128;
int pitch = 1000;
#
int main(int argc, char *argv[]){
allegro_init();
atexit(&dumb_exit);//initialize dumb
dumb_register_stdfiles(); //tELL DUMB HOW TO OPEN FILES
install_keyboard();
if(install_sound(DIGI_AUTODETECT, MIDI_NONE, "") != 0){
allegro_message("error initializing the sound system");
}
set_color_depth(16);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 1100, 550, 0, 0);
write_status_screen("Status$>_Allegro Engine Initialization Successfull");
//******************************************************************************//
//*****************************************************************************//
//Write code below this line since allegro has been initialized//
BITMAP *dragon;
BITMAP *main_title, *main_menu;
BITMAP *buffer;
/*Menu music*/
// load_sample("OG_MUSIC\\straight_outta_compton_menu.ogg");
//Setup Audiostream for Main Menu Music//
write_status_screen("Status$> Loading OG Music Stream: \"Straight Outta Compton.OGG\"");
DUH *myduh;
myduh = dumb_load_it_quick("OG_MUSIC\\straight_outta_compton_menu.ogg");
AL_DUH_PLAYER *dp = al_start_duh(myduh, 2, 0,
volume, 4096, 48000);;
//logg_get_stream("straight_outta_compton_menu.ogg", volume, pan, true);
SAMPLE *menu_guntrigger = load_sample("OG_MUSIC\\gun_menu_choose.wav");
/*Menu count*/
int menct = 0;
buffer = create_bitmap(1100, 480);
textprintf_ex(screen, font, 0, 0, WHITE, 0, "Resolution = %ix%i ", SCREEN_W, SCREEN_H);
dragon = load_bitmap("BITMAPS\\COMPTON_START_MENU_FADED_TWO.bmp", NULL);
main_title = load_bitmap("BITMAPS\\OGM_TITLE.bmp", NULL);
main_menu = load_bitmap("BITMAPS\\MAIN_MENU.bmp", NULL);
write_status_screen("Status$>_Bitmaps loaded into memory!");
write_status_screen("Status$> Loading OG Sound Effects......:");
rest(650);
rest(700);
int frames_drawn = 0;
while(!key[KEY_ESC]){
/*Handle Controls First modulus 2 to make selection easier, every second frame, keypress is captured. DO NOT DO THIS FOR ACTUAL GAMEPLAY*/
if(key[KEY_UP] && frames_drawn % 2 == 0){
play_sample(menu_guntrigger, volume, pan, pitch, FALSE);
menct--;
} else if (key[KEY_DOWN] && frames_drawn % 3 == 0){
play_sample(menu_guntrigger, volume, pan, pitch, FALSE);
menct++;
}
if (menct > 3){
play_sample(menu_guntrigger, volume, pan, pitch, FALSE);
menct = 0;
}else if (menct <0){
play_sample(menu_guntrigger, volume, pan, pitch, FALSE);
menct = 3;
}
rest(10);
//Erase everything
clear(buffer);
//status box
rectfill(screen, 0, 480, 1100, 483, WHITE);
/*Draw the frame based on user input*/
draw_sprite(buffer, dragon, 0, 0);
draw_sprite(buffer, main_title, 315, 10);
drawframe(buffer, main_menu, 485, 145, 332, 305, 0, 0, 4, menct);
//blit(main_title, screen, 0, 0, 50, 50, 540, 96);
//masked_blit(main_title, screen, 0, 0, 50, 50, 540, 96);
//masked_blit(source, dest, framex, framey, x, y, width, height);
textprintf_ex(buffer, font, 900, 470, WHITE, 0, "Written By: Kelvin Silva", bitmap_color_depth(screen));
textprintf_ex(buffer, font, 0, 470, WHITE, 0, "Frames Drawn: %i", frames_drawn);
blit(buffer, screen, 0, 0, 0, 0, 1100, 480);
/*pollduh*/
al_poll_duh(dp);
/*Wait for vsync, rest a little, update framecount and prompt for more input*/
vsync();
frames_drawn++;
rest(50);
}
write_status_screen("Status$>_Game Loop Ended...");
clear_status_screen();
//NOTE NEED TO SETUP MEMORY DESTRUCTION
destroy_bitmap(dragon);
destroy_bitmap(main_title);
destroy_bitmap(buffer);
allegro_exit();
return 0;
}
END_OF_MAIN()
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_start_duh':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|48|undefined reference to `al_assert'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|49|undefined reference to `al_assert'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|62|undefined reference to `play_audio_stream'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|69|undefined reference to `voice_set_priority'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|74|undefined reference to `stop_audio_stream'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_stop_duh':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|92|undefined reference to `stop_audio_stream'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_pause_duh':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|103|undefined reference to `voice_stop'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_resume_duh':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|113|undefined reference to `voice_start'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_duh_set_priority':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|123|undefined reference to `voice_set_priority'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_poll_duh':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|156|undefined reference to `get_audio_stream_buffer'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|166|undefined reference to `free_audio_stream_buffer'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|167|undefined reference to `stop_audio_stream'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|179|undefined reference to `free_audio_stream_buffer'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_duh_encapsulate_sigrenderer':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|208|undefined reference to `al_assert'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|209|undefined reference to `al_assert'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|215|undefined reference to `play_audio_stream'|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|222|undefined reference to `voice_set_priority'|
d:\programs\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.7.1\..\..\..\libaldmd.a(alplay.o)||In function `al_duh_decompose_to_sigrenderer':|
D:\Users\Kelvin_Silva\Downloads\dumb-0.9.3\dumb-0.9.3\src\allegro\alplay.c|248|undefined reference to `stop_audio_stream'|
||=== Build finished: 18 errors, 0 warnings (0 minutes, 0 seconds) ===|
DUMB requires you to link with two libraries, the core libdumb and then the aldumb "glue". Looks like you are only linking with the latter. Order matters too.
Note that DUMB is used to play MOD files (and various variants). If you want ogg support, it comes built in Allegro 4.4 if you have the official ogg libraries installed.
Also, if you are just getting started, then you should really use Allegro 5. Version 4 isn't really supported any longer and doesn't work as well on modern operating systems.

How to activate some window from external application in windows?

I want to send some keystroke to the external application, and it's work fine, but when I try to send keystroke to the child window of same external application, for some reason that doesn't work, so I need help. Let's say that we want to print clipboard text from notepad, and want to do it at one step. At code that will look like this.
#include <windows.h>
#include <stdio.h>
#include <iostream.h>
using namespace std;
int main(int argc, char* argv[]){
WinExec("notepad", 1);
Sleep(1000);
HWND handle = FindWindow("notepad",0); // it's handling as well
SetForegroundWindow(handle);
keybd_event(VK_CONTROL, 0, 0, 0); // simulate CTRL down
keybd_event(VkKeyScan('V'), 0, 0, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
Sleep(500);
keybd_event(VK_CONTROL, 0, 0, 0); // simulate CTRL down
keybd_event(VkKeyScan('P'), 0, 0, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // simulate CTRL up
Sleep(1000);
HWND handle1 = FindWindow(0, "Print"); // it wann't find "Print" window
SetForegroundWindow(handle1);
keybd_event(VK_MENU, 0, 0, 0); // simulate ALT down
keybd_event(VkKeyScan('P'), 0, 0, 0);
keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
return 0;
}
But it want to send ALT+P to "Print" window, why?
Final goal is to make little macro that send to application keystorkes (on any windows child, or parent..)
OS: WIN 7 64bit
You can probably make the existing code (sort of) work by simply removing these lines:
HWND handle1 = FindWindow(0, "Print"); // it wann't find "Print" window
SetForegroundWindow(handle1);
Remember that faked input goes to the thread which has the input focus and when you show the print dialog in Notepad, that dialog will gain the input focus. You simply do not need to set the focus, the system will do that for you.
However, the approach you are taking is incredibly brittle. I suspect that you would be far better served by using something like UI Automation.

How do I programmatically get the shortcut keys reserved by Mac OS X

I'm working with an application that allows the customer to customize what shortcut keys are assigned. One thing I want to do is warn if a shortcut key is chosen that is already in use by Mac OS X.
I'm trying to work with CopySymbolicHotKeys, but I'm not sure that I'm using it correctly as it lists commands as being reserved even though I do not see it listed in the "Keyboard Shortcuts" tab-pane of the "Keyboard & Mouse" System Preferences. I would like to be able to get those shortcuts that are "reserved" for system use, is this the API to use?
I've included a sample of my code below, please look at it an offer any suggestion that may come to your mind.
CFArrayRef hotkeyArray = NULL;
OSStatus status = CopySymbolicHotKeys(&hotkeyArray);
if (noErr == status && NULL != hotkeyArray) {
CFIndex hotKeyCount = CFArrayGetCount(hotkeyArray);
for (CFIndex i = 0; i < hotKeyCount; i++) {
CFDictionaryRef hotKeyDict = (CFDictionaryRef) CFArrayGetValueAtIndex(hotkeyArray, i);
if (hotKeyDict && CFGetTypeID(hotKeyDict) == CFDictionaryGetTypeID()) {
if (kCFBooleanTrue == (CFBooleanRef) CFDictionaryGetValue(hotKeyDict, kHISymbolicHotKeyEnabled)) {
SInt32 keyModifiers = 0;
CFNumberRef cfkeyModifers = (CFNumberRef) CFDictionaryGetValue(hotKeyDict, kHISymbolicHotKeyModifiers);
CFNumberGetValue(cfkeyModifers, kCFNumberSInt32Type, &keyModifiers);
bool keyIsCommandOnly = (keyModifiers == (keyModifiers & cmdKey));
bool keyIsCommandAndOption = (keyModifiers == (keyModifiers & (cmdKey | optionKey)));
CFNumberRef cfKeyCode = (CFNumberRef) CFDictionaryGetValue(hotKeyDict, kHISymbolicHotKeyCode);
short keyCode = 0;
CFNumberGetValue(cfKeyCode, kCFNumberShortType, &keyCode);
CFStringRef keyString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%C"), keyCode);
const char* commandOnlyStr = "Command";
const char* commandAndOptionStr = "Command-Option";
const char* otherStr = "Other Modifier Key";
char* modifierStr = otherStr;
if (keyIsCommandOnly) {
modifierStr = commandOnlyStr;
}
else if (keyIsCommandAndOption) {
modifierStr = commandAndOptionStr;
}
CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Mac OS X Reserved Key: %s %#"), modifierStr, keyString);
CFShow(debugString); // Command-O, Command-W and other apparently non-reserved keys are output
CFRelease(debugString);
CFRelease(keyString);
}
}
}
}
CFRelease(hotkeyArray);
I would like to add code that helps to read/write to ~/Library/Preferences/com.apple.symbolichotkeys.plist file in the way represented by Lyndsey Ferguson using CFPreferencesCopyAppValue() and than CFDictionaryGetValueIfPresent() from CFPropertyListRef. The crucial thing is to know which symbolic hot keys identifier is related with which hot keys in Keyboard Shortcuts preferences pane. Here is the code with descriptive constants that can help you a lot with this:
/**
* Apple Symbolic HotKeys Ids
* To find this symbolic hot keys indices do:
* 1. open Terminal
* 2. restore defaults in System Preferences > Keyboard > Shortcuts
* 3. defaults read com.apple.symbolichotkeys > current.txt
* 4. enable/disable given symbolic hot key in System Preferences > Keyboard > Shortcuts
* 5. defaults read com.apple.symbolichotkeys | diff -C 5 current.txt -
* 6. restore defaults in System Preferences > Keyboard > Shortcuts
*/
enum {
kSHKMoveFocusToTheMenuBar = 7, // Ctrl, F2
kSHKMoveFocusToTheDock = 8, // Ctrl, F3
kSHKMoveFocusToActiveOrNextWindow = 9, // Ctrl, F4
kSHKMoveFocusToTheWindowToolbar = 10, // Ctrl, F5
kSHKMoveFocusToTheFloatingWindow = 11, // Ctrl, F6
kSHKTurnKeyboardAccessOnOrOff = 12, // Ctrl, F1
kSHKChangeTheWayTabMovesFocus = 13, // Ctrl, F7
kSHKTurnZoomOnOrOff = 15, // Opt, Cmd, 8
kSHKZoomIn = 17, // Opt, Cmd, =
kSHKZoomOut = 19, // Opt, Cmd, -
kSHKInvertColors = 21, // Ctrl, Opt, Cmd, 8
kSHKTurnImageSmoothingOnOrOff = 23, // Opt, Cmd, Backslash "\"
kSHKIncreaseContrast = 25, // Ctrl, Opt, Cmd, .
kSHKDecreaseContrast = 26, // Ctrl, Opt, Cmd, ,
kSHKMoveFocusToNextWindow = 27, // Cmd, `
kSHKSavePictureOfScreenAsAFile = 28, // Shift, Cmd, 3
kSHKCopyPictureOfScreenToTheClipboard = 29, // Ctrl, Shift, Cmd, 3
kSHKSavePictureOfSelectedAreaAsAFile = 30, // Shift, Cmd, 4
kSHKCopyPictureOfSelectedAreaToTheClipboard = 31, // Ctrl, Shift, Cmd, 4
kSHKMissionControl = 32, // Ctrl, Arrow Up
kSHKApplicationWindows = 33, // Ctrl, Arrow Down
kSHKShowDesktop = 36, // F11
kSHKMoveFocusToTheWindowDrawer = 51, // Opt, Cmd, `
kSHKTurnDockHidingOnOrOff = 52, // Opt, Cmd, D
kSHKMoveFocusToStatusMenus = 57, // Ctrl, F8
kSHKTurnVoiceOverOnOrOff = 59, // Cmd, F5
kSHKSelectThePreviousInputSource = 60, // Ctrl, Space bar
kSHKSelectNextSourceInInputMenu = 61, // Ctrl, Opt, Space bar
kSHKShowDashboard = 62, // F12
kSHKShowSpotlightSearch = 64, // Cmd, Space bar
kSHKShowFinderSearchWindow = 65, // Opt, Cmd, Space bar
kSHKLookUpInDictionary = 70, // Shift, Cmd, E
kSHKHideAndShowFrontRow = 73, // Cmd, Esc
kSHKActivateSpaces = 75, // F8
kSHKMoveLeftASpace = 79, // Ctrl, Arrow Left
kSHKMoveRightASpace = 81, // Ctrl, Arrow Right
kSHKShowHelpMenu = 98, // Shift, Cmd, /
kSHKSwitchToDesktop1 = 118, // Ctrl, 1
kSHKSwitchToDesktop2 = 119, // Ctrl, 2
kSHKSwitchToDesktop3 = 120, // Ctrl, 3
kSHKSwitchToDesktop4 = 121, // Ctrl, 4
kSHKShowLaunchpad = 160, //
kSHKShowAccessibilityControls = 162, // Opt, Cmd, F5
kSHKShowNotificationCenter = 163, //
kSHKTurnDoNotDisturbOnOrOff = 175, //
kSHKTurnFocusFollowingOnOrOff = 179, //
};
struct symbolic_hot_keys {
int shk_id; // symbolic hot keys identifier
int enabled;
char *type; // usually "standard"
int64_t ASCII_code; // ASCII code of the character or 65535 (0xFFFF) for non-ASCII characters
int64_t virtual_key_code; // virtual key code for the character
int64_t modifier_keys_flags; // the sum of modifier key flags: Shift 17 bit, Ctrl 18 bit, Opt 19 bit, Cmd 20 bit
};
typedef struct symbolic_hot_keys symbolic_hot_keys_t;
// simple mapping of modifier flags
enum {
kMFShift = kCGEventFlagMaskShift,
kMFControl = kCGEventFlagMaskControl,
kMFOption = kCGEventFlagMaskAlternate,
kMFCommand = kCGEventFlagMaskCommand,
};
I don't think that this is possible.
This link discusses using CopySymbolicHotKeys as well. However, the function lists keyboard shortcuts that are not listed in the System Preference for Keyboard Shortcuts. If there was someway to differentiate between actually reserved keys and just standard keys, that would be ideal.
The best answer seems to be parsing the actual plist file, "com.apple.symbolichotkeys.plist" which I found in Apple's Carbon Email Discussion List. However, this answer assumes that you know what each and every key is (which I don't).
I also found a link describing what the modifier key values are.
Here is the code that was posted for disabling a known key in the System Shortcut Key Preferenes:
#include <CoreServices/CoreServices.h>
static CFStringRef gApplicationID = CFSTR("com.apple.symbolichotkeys");
static CFStringRef gKeyASHK = CFSTR("AppleSymbolicHotKeys");
static CFStringRef gKey73 = CFSTR("73");
static CFStringRef gKeyEnabled = CFSTR("enabled");
int main(int argc, const char *argv[]) {
#pragma unused (argc, argv)
CFPropertyListRef hotkeysCFPropertyListRef = CFPreferencesCopyAppValue(gKeyASHK, gApplicationID);
if ( !hotkeysCFPropertyListRef ) {
fprintf(stderr,
"%s, CFPreferencesCopyAppValue(\"AppleSymbolicHotKeys\", \"com.apple.symbolichotkeys.plist\" returned NULL.\n",
__PRETTY_FUNCTION__);
return (-1);
}
// make sure it's a dictionary
if ( CFGetTypeID(hotkeysCFPropertyListRef) != CFDictionaryGetTypeID() ) {
fprintf(stderr, "%s, CFGetTypeID(hotkeysCFPropertyListRef) != CFDictionaryGetTypeID().\n", __PRETTY_FUNCTION__);
return (-1);
}
// get the "73" value from that dictionary
CFPropertyListRef hotkey73CFPropertyListRef = NULL;
if ( !CFDictionaryGetValueIfPresent(hotkeysCFPropertyListRef, gKey73, &hotkey73CFPropertyListRef) ) {
fprintf(stderr, "%s, CFDictionaryGetValueIfPresent(...,\"73\",...) returned FALSE.\n", __PRETTY_FUNCTION__);
return (-1);
}
//CFShow(hotkey73CFPropertyListRef);
// make sure it's a dictionary
if ( CFGetTypeID(hotkey73CFPropertyListRef) != CFDictionaryGetTypeID() ) {
fprintf(stderr, "%s, CFGetTypeID(hotkey73CFPropertyListRef) != CFDictionaryGetTypeID().\n", __PRETTY_FUNCTION__);
return (-1);
}
// get the "73" value from that dictionary
CFPropertyListRef hotkey73EnabledCFPropertyListRef = NULL;
if ( !CFDictionaryGetValueIfPresent(hotkey73CFPropertyListRef, gKeyEnabled, &hotkey73EnabledCFPropertyListRef) ) {
fprintf(stderr, "%s, CFDictionaryGetValueIfPresent(...,\"enabled\",...) returned FALSE.\n", __PRETTY_FUNCTION__);
return (-1);
}
//CFShow(hotkey73EnabledCFPropertyListRef);
// make sure it's a boolean
if ( CFGetTypeID(hotkey73EnabledCFPropertyListRef) != CFBooleanGetTypeID() ) {
fprintf(stderr, "%s, CFGetTypeID(hotkey73EnabledCFPropertyListRef) != CFBooleanGetTypeID().\n", __PRETTY_FUNCTION__);
return (-1);
}
// get its value
Boolean value = CFBooleanGetValue(hotkey73EnabledCFPropertyListRef);
CFBooleanRef hotkey73EnabledCFBooleanRef = value ? kCFBooleanFalse : kCFBooleanTrue; // note: toggle value
// create a mutable copy of the hot key 73 dictionary
CFMutableDictionaryRef newHotkey73CFCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, hotkey73CFPropertyListRef);
if ( !newHotkey73CFCFMutableDictionaryRef ) {
fprintf(stderr, "%s, CFDictionaryCreateMutableCopy(..., hotkey73CFPropertyListRef) returned NULL.\n", __PRETTY_FUNCTION__);
return (-1);
}
// set the new value for the "enabled" item
CFDictionarySetValue(newHotkey73CFCFMutableDictionaryRef, gKeyEnabled, hotkey73EnabledCFBooleanRef);
//CFShow(newHotkey73CFCFMutableDictionaryRef);
// create a mutable copy of the hot key dictionary
CFMutableDictionaryRef newHotkeysCFPropertyListRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, hotkeysCFPropertyListRef);
if ( !newHotkeysCFPropertyListRef ) {
fprintf(stderr, "%s, CFDictionaryCreateMutableCopy(...,hotkeysCFPropertyListRef) returned NULL.\n", __PRETTY_FUNCTION__);
return (-1);
}
// set the new value for the "73" item
CFDictionarySetValue(newHotkeysCFPropertyListRef, gKey73, newHotkey73CFCFMutableDictionaryRef);
CFRelease(newHotkey73CFCFMutableDictionaryRef);
//CFShow(newHotkeysCFPropertyListRef);
CFPreferencesSetAppValue(gKeyASHK, newHotkeysCFPropertyListRef, gApplicationID);
if ( !CFPreferencesAppSynchronize(gApplicationID) ) {
fprintf(stderr, "%s, CFPreferencesAppSynchronize returned false.\n", __PRETTY_FUNCTION__);
return (-1);
}
// note: value is opposite of what we just set (so invert logic)
printf("%s, /AppleSymbolicHotKeys/73/enabled set to %s.\n", __PRETTY_FUNCTION__, value ? "FALSE" : "TRUE");
return (0);
} // main
I wouldn't know how to do it programmically but if hard-coding is an option you'll find a list of MacOSX shortcuts here: http://support.apple.com/kb/HT1343 . I'd use a regex to suck out the key-combinations then programmically convert to keysyms/keycodes. The page appears to be updated by Apple for each OSX release so you should be able to easily repeat the process with each OSX update.

Resources