<commit_before>/**
 * @file key_event_hook.c
 * @author <NAME> (<EMAIL>)
 *
 * Hook GDK key press/release events and replace non-Latin keyvals
 * with whey Latin equivalents
 */

/* To allow defining of RTLD_NEXT in dlfcn.h */
#define _GNU_SOURCE

#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>

//
// Private Definitions
//

#if ENABLE_DEBUG
#define PRINT_DEBUG(message, ...)			printf("%s:%d: " message, __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define PRINT_DEBUG(message, ...)
#endif

//
// Private Types
//

/**
 * Prototype of gdk_event_handler_set function
 */
typedef void (*GdkEventHandlerSet)(GdkEventFunc func, gpointer data, GDestroyNotify  notify);

//
// Private Variables
//

/**
 * Pointer to original gdk_event_handler_set function
 */
static GdkEventHandlerSet gdk_event_handler_set_orig = NULL;

/**
 * Application handler of GDK events
 */
static GdkEventFunc gdk_event_handler = NULL;

/**
 * Key group of Latin layout
 */
static gint latin_key_group = -1;

//
// Private Services
//

/**
 * Determine key group of Latin layout
 * @return Latin key group
 */
static gint get_latin_key_group(void)
{
	gint result = 0;
	GArray *group_keys_count = g_array_new(FALSE, TRUE, sizeof(gint));

	// count all key groups for Latin alphabet
	for (guint keycode = GDK_KEY_a; keycode <= GDK_KEY_z; keycode++)
	{
		GdkKeymapKey* keys;
		gint n_keys;
		if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), GDK_KEY_A, &keys, &n_keys))
		{
			for (gint key = 0; key < n_keys; key++)
			{
				if (keys->group >= 0 && (guint) keys->group >= group_keys_count->len)
					g_array_set_size(group_keys_count, keys->group + 1);
			}
			g_array_index(group_keys_count, gint, keys->group)++;
			g_free(keys);
		}
	}

	// group with maximum keys count is Latin
	int max_keys_count = 0;
	for (guint group = 0; group < group_keys_count->len; group++)
	{
		if (g_array_index(group_keys_count, gint, group) > max_keys_count)
		{
			result = group;
			max_keys_count = g_array_index(group_keys_count, gint, group);
		}
	}

	g_array_free(group_keys_count, TRUE);

	return result;
}

static void on_gdk_keys_changed(GdkKeymap *keymap, gpointer user_data)
{
	PRINT_DEBUG("on_gdk_keys_changed\n");
	latin_key_group = get_latin_key_group();
	PRINT_DEBUG("Latin key group is %d\n", latin_key_group);
}

/**
 * Key events filter. Replace key group and keyval with Latin equivalents when key pressed with Alt or Ctrl modifiers.
 */
static void key_events_hook(GdkEvent *event, gpointer data)
{
	if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
	{
		if (latin_key_group == -1)
		{
			latin_key_group = get_latin_key_group();
			PRINT_DEBUG("Latin key group is %d\n", latin_key_group);
			g_signal_connect(G_OBJECT(gdk_keymap_get_default()), "keys-changed", G_CALLBACK(on_gdk_keys_changed), NULL);
		}
		if ((event->key.state & GDK_CONTROL_MASK) && !event->key.is_modifier && event->key.group != latin_key_group)
		{
			PRINT_DEBUG("non-Latin hotkey event with keyval=%d\n", event->key.keyval);
			GdkKeymapKey *keys;
			guint *keyvals;
			gint n_entries;
			gint level;

			if (gdk_keymap_translate_keyboard_state(NULL, event->key.hardware_keycode, event->key.state,
					event->key.group, NULL, NULL, &level, NULL)
					&& gdk_keymap_get_entries_for_keycode(NULL, event->key.hardware_keycode,
							&keys, &keyvals, &n_entries))
			{
				gint i;
				for (i = 0; i < n_entries; i++)
				{
					PRINT_DEBUG("group: %d, level: %d, keycode: %d\n", keys[i].group, keys[i].level, keys[i].keycode);
					if (keys[i].group == latin_key_group && keys[i].level == level)
					{
						// found Latin key - modify event data
						PRINT_DEBUG("found Latin keyval=%d\n", keyvals[i]);
						event->key.group = keys[i].group;
						event->key.keyval = keyvals[i];
						break;<commit_msg>Support keybindings with Alt key<commit_after>/**
 * @file key_event_hook.c
 * @author <NAME> (<EMAIL>)
 *
 * Hook GDK key press/release events and replace non-Latin keyvals
 * with whey Latin equivalents
 */

/* To allow defining of RTLD_NEXT in dlfcn.h */
#define _GNU_SOURCE

#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>

//
// Private Definitions
//

#if ENABLE_DEBUG
#define PRINT_DEBUG(message, ...)			printf("%s:%d: " message, __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define PRINT_DEBUG(message, ...)
#endif

//
// Private Types
//

/**
 * Prototype of gdk_event_handler_set function
 */
typedef void (*GdkEventHandlerSet)(GdkEventFunc func, gpointer data, GDestroyNotify  notify);

//
// Private Variables
//

/**
 * Pointer to original gdk_event_handler_set function
 */
static GdkEventHandlerSet gdk_event_handler_set_orig = NULL;

/**
 * Application handler of GDK events
 */
static GdkEventFunc gdk_event_handler = NULL;

/**
 * Key group of Latin layout
 */
static gint latin_key_group = -1;

//
// Private Services
//

/**
 * Determine key group of Latin layout
 * @return Latin key group
 */
static gint get_latin_key_group(void)
{
	gint result = 0;
	GArray *group_keys_count = g_array_new(FALSE, TRUE, sizeof(gint));

	// count all key groups for Latin alphabet
	for (guint keycode = GDK_KEY_a; keycode <= GDK_KEY_z; keycode++)
	{
		GdkKeymapKey* keys;
		gint n_keys;
		if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), GDK_KEY_A, &keys, &n_keys))
		{
			for (gint key = 0; key < n_keys; key++)
			{
				if (keys->group >= 0 && (guint) keys->group >= group_keys_count->len)
					g_array_set_size(group_keys_count, keys->group + 1);
			}
			g_array_index(group_keys_count, gint, keys->group)++;
			g_free(keys);
		}
	}

	// group with maximum keys count is Latin
	int max_keys_count = 0;
	for (guint group = 0; group < group_keys_count->len; group++)
	{
		if (g_array_index(group_keys_count, gint, group) > max_keys_count)
		{
			result = group;
			max_keys_count = g_array_index(group_keys_count, gint, group);
		}
	}

	g_array_free(group_keys_count, TRUE);

	return result;
}

static void on_gdk_keys_changed(GdkKeymap *keymap, gpointer user_data)
{
	PRINT_DEBUG("on_gdk_keys_changed\n");
	latin_key_group = get_latin_key_group();
	PRINT_DEBUG("Latin key group is %d\n", latin_key_group);
}

/**
 * Key events filter. Replace key group and keyval with Latin equivalents when key pressed with Alt or Ctrl modifiers.
 */
static void key_events_hook(GdkEvent *event, gpointer data)
{
	if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
	{
		if (latin_key_group == -1)
		{
			latin_key_group = get_latin_key_group();
			PRINT_DEBUG("Latin key group is %d\n", latin_key_group);
			g_signal_connect(G_OBJECT(gdk_keymap_get_default()), "keys-changed", G_CALLBACK(on_gdk_keys_changed), NULL);
		}
		if ((event->key.state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) && !event->key.is_modifier
				&& event->key.group != latin_key_group)
		{
			PRINT_DEBUG("non-Latin hotkey event with keyval=%d\n", event->key.keyval);
			GdkKeymapKey *keys;
			guint *keyvals;
			gint n_entries;
			gint level;

			if (gdk_keymap_translate_keyboard_state(NULL, event->key.hardware_keycode, event->key.state,
					event->key.group, NULL, NULL, &level, NULL)
					&& gdk_keymap_get_entries_for_keycode(NULL, event->key.hardware_keycode,
							&keys, &keyvals, &n_entries))
			{
				gint i;
				for (i = 0; i < n_entries; i++)
				{
					PRINT_DEBUG("group: %d, level: %d, keycode: %d\n", keys[i].group, keys[i].level, keys[i].keycode);
					if (keys[i].group == latin_key_group && keys[i].level == level)
					{
						// found Latin key - modify event data
						PRINT_DEBUG("found Latin keyval=%d\n", keyvals[i]);
						event->key.group = keys[i].group;
						event->key.keyval = keyvals[i];
						break;
{'fraction_non_alphanumeric': 0.1354988999611751, 'fraction_numerical': 0.0024589103144816876, 'mean_word_length': 4.060903732809431, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3999402', 'n_tokens_mistral': 3183, 'n_tokens_neox': 2888, 'n_words': 654}