GTK: "key-press-event" handling while Shift is pressed - c

I'm writing a small program: it's a lone drop-down menu with lowercase letters as menuitem labels:
If you hold Shift, the labels become capitalized (I wrote a "key-press-event" and "key-release-event" handler for this). The problem is that while Shift is pressed, I still want to navigate the menu and choose items with Enter press. The default handlers aren't get triggered if some modifier is pressed, so I handle it in the following way:
static gboolean menu_key_event(GtkWidget *menu, GdkEvent *event, gpointer data) {
(void)data;
GdkEventKey *key_event = (GdkEventKey*)event;
switch (key_event->keyval) {
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R: ;
bool b = (key_event->type == GDK_KEY_PRESS) ? true : false;
gtk_container_foreach(GTK_CONTAINER(menu), menuitem_capitalize_label, &b);
return TRUE;
break;
case GDK_KEY_Return:
if ((key_event->type == GDK_KEY_PRESS) &&
(key_event->state & GDK_SHIFT_MASK)) {
// I want default callback to handle this
g_signal_emit_by_name(menu, "activate-current");
return TRUE;
}
break;
case GDK_KEY_Up:
case GDK_KEY_Down:
if ((key_event->type == GDK_KEY_PRESS) &&
(key_event->state & GDK_SHIFT_MASK)) {
// Some function I wrote to fiddle with menu items,
// simulating default selection behavior
menu_rotate_selection(GTK_MENU_SHELL(menu), key_event->keyval);
return TRUE;
}
break;
}
return FALSE;
}
Could this be done in a more elegant fashion? In short, I want my application handle Enter, arrow keys and Shift+Enter, Shift+ arrow keys the same way without needing to manually process it.

I've finally found needed signal to select menuitems ("move-current"), so my own menu_rotate_selection function is no longer needed. That signal name is confusing though, I'd rather think its purpose to actually move the menuitem itself whithin the menu (first I thought the other obscure-named signal "cycle-focus" is for changing selection). Now it can be rewriten as following:
...
case GDK_KEY_Up:
case GDK_KEY_Down:
if ((key_event->type == GDK_KEY_PRESS) &&
(key_event->state & GDK_SHIFT_MASK)) {
GtkMenuDirectionType dir = (key_event->keyval == GDK_KEY_Up) ?
GTK_MENU_DIR_PREV : GTK_MENU_DIR_NEXT;
g_signal_emit_by_name(menu, "move-current", dir);
return TRUE;
}
break;
...
This pretty much answers my question.

Related

how the setting of AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM relate to result of getResources().getConfiguration().uiMode

when using
getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK
to check what mode the app is currently in,
int currentNightMode = getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
// Night mode is not active, we're in day time
case Configuration.UI_MODE_NIGHT_YES:
// Night mode is active, we're at night!
case Configuration.UI_MODE_NIGHT_UNDEFINED:
// We don't know what mode we're in, assume notnight
}
if called this with AppCompatDelegate.MODE_NIGHT_YES earlier
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
is the return of currentNightMode to be Configuration.UI_MODE_NIGHT_YES?
what it would return when the AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM was set before
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
and the device has changed from light to dark them (or from dark to light)?
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
tells current what mode the app will be in.
when
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
if change the system theme in settings (in Android Q),
the configuration.uiMode will reflect the change.
same with the
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
or
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
note: the configuration.uiMode change will trigger a config change and may cause recreate the activity.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
themeSystem.setVisibility(View.VISIBLE);
} else {
themeSystem.setVisibility(View.GONE);
}
switch (sharePref.getTheme()) {
case THEME_LIGHT:
themeLight.setChecked(true);
break;
case THEME_DARK:
themeDark.setChecked(true);
break;
case THEME_SYSTEM:
themeSystem.setChecked(true);
break;
default:
switch (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
case Configuration.UI_MODE_NIGHT_NO:
themeLight.setChecked(true);
break;
case Configuration.UI_MODE_NIGHT_YES:
themeDark.setChecked(true);
break;
case Configuration.UI_MODE_NIGHT_UNDEFINED:
themeLight.setChecked(true);
break;
}
}
themeGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.themeLight:
setTheme(AppCompatDelegate.MODE_NIGHT_NO, THEME_LIGHT);
break;
case R.id.themeDark:
setTheme(AppCompatDelegate.MODE_NIGHT_YES, THEME_DARK);
break;
case R.id.themeSystem:
setTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, THEME_SYSTEM);
break;
}
}
});

Multiple Timers Arduino

Hi I had a question about timers on that Arduino.
I have 5 physical buttons (piezos) that I am getting the analog input from. I am then having them write out a keyboard key. My issue is when one is hit I want it to be unable to hit for "x" amount of time. I tried using delay, but this ended up delaying the whole program, thus 2 buttons could not be hit at the same time. Could someone explain to me how to do this with timers? I want 5 separate timers 1 for each button that controls a Boolean, I would need 5 separate timers for 5 separate if statements. (See code).
//SNARE LOOP2
if(sensorValueA0 == 0)
{
if(SnareHit == false)
{
Keyboard.write(115);
SnareHit = true;
//Use timer here to delay this part of the system
SnareHit = false;
}
}
//BASS DRUM LOOP
if(sensorValueA1 == 0)
{
if(BassHit == false)
{
Keyboard.write(98);
BassHit = true;
//Use timer here to delay this part of the system
BassHit = false;
}
}
Thanks.
You can use the millis() function, something similar to the following code:
if(ButtonPress==true){
time=millis() //time was previously declared as unsigned long
if(time>=5000){ //5000 = 5 sec
ButtonPress==false
}
}
It will not stop the arduino loop as dealy() does.
More info: http://playground.arduino.cc/Code/AvoidDelay
Perhaps you are trying to de-bounce the button. I usually do this in the main loop, and expect 5 consecutive "pressed" reads before I say the button is really pressed, something like this:
int button1PressedCount = 0;
int debounceCounter = 5; // Number of successive reads before we say the switch is pressed
boolean buttonPressed = false;
int inputPin1 = 7;
void setup() {
// Grounding the input pin causes it to actuate
pinMode(inputPin1, INPUT ); // set the input pin 1
digitalWrite(inputPin1, HIGH); // set pin 1 as a pull up resistor.
}
void loop()
{
// Some code
// Check button, we evaluate below
checkButton();
// Some more code
}
void checkButton() {
if (digitalRead(inputPin) == 0) {
// We need consecutive pressed counts to treat this is pressed
if (button1PressedCount < debounceCounter) {
button1PressedCount += 1;
// If we reach the debounce point, mark the start time
if (button1PressedCount == debounceCounter) {
// Button is detected as pressed!
buttonPressed = true;
}
}
} else {
if (button1PressedCount == debounceCounter) {
// We were pressed, but are not any more
buttonPressed = false;
}
button1PressedCount = 0;
}
}
Also it seems using an analogue input with a check if the analogue value is exactly equal to 0 might be a bit sensitive in noisy environments. This is why I use a digital input and the internal pull up resistor.

how to check the radio button is checked or not in windows form

I have 3 pair of radiobutton at my form I want to check at every group of radiobutton one radiobutton is checked when user press save button. I used the below code to check every radiobutton, but I think this one a better approach to check.
if (radioBttnAddrssCoYes.Checked || rdoBttnAddCorrectNo.Checked)
{
if (rdoGroundFloorTrue.Checked || radioGroundFFalse.Checked)
{
if (rdoHomeTrue.Checked || radioMeet.Checked)
{
// Here I do something
}
else
{
MessageBox.Show("Please check Customer All day At Home");
}
}
else
{
MessageBox.Show("Please Check Ground Floor Delivery");
}
}
else
{
MessageBox.Show("Check Addresss Correct");
}
Thanks For your support and help
I would probably do it a little different, but it doesn't mean your way is wrong.
if(VaildateRadioGroupIsChecked(radioBttnAddrssCoYes, rdoBttnAddCorrectNo, "Check Addresss Correct") &&
VaildateRadioGroupIsChecked(rdoGroundFloorTrue, radioGroundFFalse, "Please Check Ground Floor Delivery") &&
VaildateRadioGroupIsChecked(rdoHomeTrue, radioMeet, "Please check Customer All day At Home"))
{
// do your thing...
}
private bool VaildateRadioGroupIsChecked(RadioButton a, RadioButton b, string MessageToUser)
{
if(!a.Checked && !b.Checked) {
Messagebox.Show(MessageToUser);
return false;
}
return true;
}
Of course, you can develop it further and not send the 2 radio buttons to the function, but it's containing element. this way, if you have 3, 4, or n radio buttons you can check all of them in one simple call.
Another well known technique to validate that a radio box is checked is to simply hold a boolean variable on the form level that is false by default, and changed to true when any of the radio buttons is checked. However, this technique will not serve you well in this case, since you will need 3 boolean variables for that, and the code will be unnecessary complicated comparing to the other solutions.
To answer your question in the comment, I would probably do something like that:
string MessageToUser = VaildateRadioGroupIsChecked(radioBttnAddrssCoYes, rdoBttnAddCorrectNo, "Check Addresss Correct") +
VaildateRadioGroupIsChecked(rdoGroundFloorTrue, radioGroundFFalse, "Please Check Ground Floor Delivery") +
VaildateRadioGroupIsChecked(rdoHomeTrue, radioMeet, "Please check Customer All day At Home");
if(MessageToUser.Length == 0) {
// do your stuff
} else {
Messagebox.Show(MessageToUser);
}
private string VaildateRadioGroupIsChecked(RadioButton a, RadioButton b, string MessageToUser)
{
if(!a.Checked && !b.Checked) {
return MessageToUser + "\n";
}
return string.Empty;
}
You could rewrite it to the following if you find it more readable and want to display custom messages to the User when some radios of a group are not checked.
if (! (rdoHomeTrue.Checked || radioMeet.Checked)) {
MessageBox.Show("Please check Customer All day At Home");
return;
}
if (! (rdoGroundFloorTrue.Checked || radioGroundFFalse.Checked)) {
MessageBox.Show("Please Check Ground Floor Delivery");
return;
}
if (! (radioBttnAddrssCoYes.Checked || rdoBttnAddCorrectNo.Checked)) {
MessageBox.Show("Check Addresss Correct");
return;
}
// here i do something

Ncurses menu - remembering selection

I am using Ncurses library to do some interactive menus, and I don't know how to do one thing. I have simple menu with few options, I turned of O_ONEVALUE so many options can be selected at the same time, before posting menu I get all the menu items and mark them as selected or not, depending on a bit mask that I keep stored somewhere else, but when the menu is posted every option is turned off, here is the code:
//acquiring menu items
ITEM** header_items = menu_items(params.header_opts_menu);
ITEM* cur_item;
if (header_items == NULL)
{
client_cleanup();
syslog_nsys_f(LOG_ERR, "error while getting header menu items");
}
//selecting appropriate items
long header_menu_items_count = ARRAY_SIZE(header_menu_choices);
for (i = 0; i < header_menu_items_count; ++i)
{
if ((params.header_flags & (1 << (i))) != 0)
decision = TRUE;
else
decision = FALSE;
if (set_item_value(header_items[i], TRUE) != E_OK)
{
client_cleanup();
syslog_nsys_f(LOG_ERR,"error while setting menu item value");
}
}
if (post_menu(params.header_opts_menu) != E_OK)
{
client_cleanup();
syslog_nsys_f(LOG_ERR,"error while posting header options menu");
}
set_menu_items(params.header_opts_menu,header_items);
refresh();
even if I set value of every item to TRUE nothing happens, where is my mistake?
It looks like you are attempting to call set_menu_items after calling post_menu. Check the return value from set_menu_items you are probably getting an E_POSTED error.

Display response time seems too slow on simple functions

I have written an application in C using GTK 2.0 for a touchscreen panel with an ARM processor running debian linux. It is a very basic application that presents a few buttons (event boxes) on screen that can be clicked. On one page, I have 4 fields to present a "list" that can be scrolled through by clicking an up arrow and a down arrow (also event boxes). My function (code below) for the scrolling is very basic...it just updates each field with the next item from the array. Everything works fine, but the problem I am seeing is that if you repeatedly click the scroll button a little too quickly, it jumps ahead a few list items too far. My guess as to what is happening is that, when clicking too fast, the counter advances faster than the screen can update, so that by the time you click again it is actually updating with the then too-high counter. I wouldn't be concerned if it only happened when clicking REALLY fast, but I think the slow response seems way out of line for such a simple function repeating at a reasonably quick rate.
I'm hoping maybe someone has some input on something I might be missing in regards to screen refreshes with GTK?
Thank you in advance for any thoughts or advice!
Here is my code for my "volume-up" function and "scroll-up" function, both having the same problem. There are corresponding "scroll-down" and "volume-down" functions with the same issue:
static void sr_vol_up_clicked (GtkWidget *fakewidget, GdkEvent *fakeevent, gpointer number)
{
g_timer_start(lock_timer);
gtk_image_set_from_file (GTK_IMAGE(sr_vol_up_button),"./images/Admin/navigation_up_arrow_DOWN.png");
if (sr_current_level < 100)
{
sr_current_level = sr_current_level + 1;
gtk_label_set_text (GTK_LABEL(sr_current_level_label), (g_strdup_printf("%i", sr_current_level)));
set_sr_volume(sr_current_level);
}
gtk_image_set_from_file (GTK_IMAGE(sr_vol_up_button),"./images/Admin/navigation_up_arrow_UP.png");
}
And the other:
static void scroll_show_up ()
{
g_timer_start(lock_timer);
if (show_scroll_count > 0)
{
if (show_one_displayed - 1 < 0)
{
show_one_displayed = (show_loop_list->len -1);
}
else
{
show_one_displayed = show_one_displayed - 1;
}
gtk_label_set_text (GTK_LABEL(upcoming_show_1_label), get_show_name((char *)g_ptr_array_index(show_loop_list, show_one_displayed)));
if (show_two_displayed - 1 < 0)
{
show_two_displayed = (show_loop_list->len -1);
}
else
{
show_two_displayed = show_two_displayed - 1;
}
gtk_label_set_text (GTK_LABEL(upcoming_show_2_label), get_show_name((char *)g_ptr_array_index(show_loop_list, show_two_displayed)));
if (show_three_displayed - 1 < 0)
{
show_three_displayed = (show_loop_list->len -1);
}
else
{
show_three_displayed = show_three_displayed - 1;
}
gtk_label_set_text (GTK_LABEL(upcoming_show_3_label), get_show_name((char *)g_ptr_array_index(show_loop_list, show_three_displayed)));
if (show_four_displayed - 1 < 0)
{
show_four_displayed = (show_loop_list->len -1);
}
else
{
show_four_displayed = show_four_displayed - 1;
}
gtk_label_set_text (GTK_LABEL(upcoming_show_4_label), get_show_name((char *)g_ptr_array_index(show_loop_list, show_four_displayed)));
show_scroll_count = show_scroll_count - 1;
}
}

Resources